C语言基础再学习
C语言基础再学习
本篇属于基础知识的再学习,会略去一些已在编码中掌握的内容。
数据
这一部分的核心内容是数据的 作用域 、 链接属性 、 存储类型。
但在这之前,需要了解C语言中最基本的4种数据类型:
- 整型:包括有符号和无符号的char、short int、int、long int。
- 浮点型:单精度float和双精度double;
- 指针:用以直接操作程序内存的类型。
- 聚合类型:结构体、数组、共用体等。
short至少为16位,long至少32位。
利用tyepdef
和 #define
进行多个变量的并列声明时会有区别,从语义上来说,typedef更接近我们的真实目的。
#define char* CHAR_PTR
typedef char* char_ptr
CHAR_PTR a, b;//a的类型是char*,而b的类型是char
char_ptr c, d;//c和d都是char*类型
作用域
- 代码块作用域:定义于代码块内的标识符,其作用域自定义处开始,于此代码块末尾结束。
- 文件作用域:定义于任何代码块之外的标识符,其作用域自定义处开始,向后覆盖至文件结尾。
- 原型作用域:声明于函数参数表,防止一个原型中不止一次地使用同一个名字。
- 函数作用域
链接属性
- external:以关键字extern修饰,缺省默认,不同源文件的同名标识符都表示同一个实体。
- internal:以关键字static修饰,不同文件下的同名标识符成为两个相互独立的实体。
- none:无链接属性,所有声明都相互独立。
存储类型
- 自动:缺省默认,位于堆栈。
- 静态:以static修饰或拥有文件作用域的标识符,位于静态存储区,会被初始化为0。
- 寄存器:表示希望将数据存储于硬件寄存器中,是否如此由编译器决定。
在声明的同时进行初始化,以及先声明后初始化,这两种方式仅存在风格上的差别,在效率上没有任何差别。
语句
- 表达式语句
- if语句
- while语句
- for语句
- do语句
- switch语句
- goto语句
操作符
布尔值
C语言中没有单独的布尔类型,true和false对应的概念是 非零值 和 零值。所以不能单纯地以 0 和 1 来判断 true 和 false。
左值和右值
能出现在赋值符号=
左侧的值即为左值,能出现于赋值符号右侧的就是右值。
左值代表的是一个内存位置,所以我们能用赋值表达式修改左值标识符代表的内存位置上的数据。
右值代表的是一个数值,可以看成是常量,因而对于右值只能够取得其值,内存中没有对应的位置。
指针
指针是C语言的核心所在,通过指针,可以完成对内存的管理和访问。本质上,指针是一个用于保存地址的变量。不管是指向何种类型的指针,其大小都是固定的。我们可以通过声明,来指明指针所指向的类型,以通知编译器自己需要经过指针操作哪一种数据。
指针保存的是一个地址,也就是某一块内存的起始地址。这块内存具体取多大,则与所声明的指向的数据类型的大小一致。
因为指针也是一种变量,所以其初值与自身存储类型有关。
使用const修饰指针:
- 顶层const:指针指向的内容不可修改,但可以让指针指向其他内容,即
const T* ptr
或T const* ptr
。 - 底层const:指针只能指向初始指定的内容,但可以修改所指向的内容,即
T* const ptr
。
指针的运算
指针支持 指针与整数的加减法 、 指针之间的减法 、 指针之间的关系运算 (大小关系)。
函数
函数声明
C语言保留了旧式的函数声明,但这种声明方式不利于编译器进行语法检查,在声明与定义时应当统一采用新式的声明方式。
// 旧式函数声明
int sum_old(a, b)
int a;
int b;
{
return a + b;
}
// 新式函数声明
int sum_new(int a, int b) {
return a + b;
}
ADT
Abstract Data Type,即抽象数类型,基本思想是将模块分为 功能说明 和 接口说明。功能说明描述模块执行的任务,接口说明定义模块的使用方法。用户只能以接口形式使用模块,不能看到模块设计的细节。具体方法是以 static 修饰非接口的模块函数。
可变参数列表
C语言可以通过使用 stdarg
宏来传输可变参数列表,可以通过 va_start
、 va_arg
、 va_end
的配合使用提取可变参数列表中的值。
/*
** 计算指定数量的值的平均值。
*/
#include <stdarg.h>
float average( int n_values, ... ) {
va_list var_arg;
int count;
float sum = 0;
/*
** 准备访问可变参数。
*/
va_start( var_arg, n_values );
/*
** 添加取自可变参数列表的值。
*/
for( count = 0; count < n_values; count += 1 ){
sum += va_arg( var_arg, int );
}
/*
** 完成处理可变参数。
*/
va_end( var_arg );
return sum / n_values;
}
使用该宏时,要求至少给出一个命名参数来表示可变列表中的参数个数,而且需要自行保证这些参数类型的一致性。