目录
一 写在前面
1.1 书籍信息
作者:(美)Brian W. Kernighan / (美)Dennis M. Ritchie
原作名: The C Programming Language
1.2 简单叙述
1978 : The C Programming Language ,第1版
1983 : ANSI 建立 X3J11 委员会 (标准 C)
1988 : The C Programming Language ,第2版
1989 : C89 ,ANSI C 标准出版
笔记为第二版,译者: 徐宝文 / 李志。
笔记中的知识点可能来自书中不同的章节,略过第一章节的记录。
解释与思考部分并不全是书中的内容,也包括经验之谈、网上资料。
二 类型、运算符与表达式
2.1 变量名
变量由字母、数字组成且第一个字母不能是下划线(下划线看作字母)。
内部名长度不要超过31个字符,外部名不要超过6个字符。
C语言中的关键字不能用作变量名。
解释与思考
内部名:在本文件内使用的变量名。
外部名:文件之间相互调用的变量。
变量可以按照不同的依据进行分类,接触最多的有三种分类:
①按照变量类型进行区分,如: int型变量、long型变量、char型变量等;
②按照不同关键字进行区分,如: 静态变量(static)、自动变量(auto)、寄存器变量(register)、外部变量(extern)
static修饰的变量有两种情况:
a: 修饰局部变量时,该变量会一直占用存储空间,伴随程序的整个运行周期;
b: 修饰全局变量时,将会限定该变量只在本文件中使用。
auto修饰的变量存在于栈区。
register修饰的变量存在于寄存器中,不能寻址
举例:
extern修饰的变量有两种情况:
a:该变量在其他文件中定义,想在本文件中使用,需要加extern声明
b: 在变量未定义之前就使用,需要在定义时加extern声明
③按照变量的作用域区分,如全局变量、局部变量
全局变量能够作用与程序的始终
局部变量只能作用于函数体内
三种变量分类之间相互交叉,可以根据变量的不同修饰词对变量的特点进行判断
如:静态变量既可以是全局的也可以是局部的;
int型变量可以全局的也可以是局部的等等;
静态局部变量只能函数内使用,但是存在于 .data 或 .bss段,因此生命周期贯穿程序始终。
———————————————————————————————
2.2 数据类型及长度
基本类型 char、int、float(单精度浮点型)、double(双精度浮点型)
修饰词short、long、unsigned、signed
解释与思考
short 与 long其实是short int与long int 的缩写,用来满足不同长度的整型数
short与int至少16位,long至少32位,长度之间应满足 short =< int =< long
float、double、long double(高精度浮点型)三者之间可以表示为相同的长度或者三种不同的长度,取决于具体实现
———————————————————————————————
2.3 常量
———————————————————————————————
2.4 声明
声明:指明一种数据类型
初始化:变量名后面紧跟一个等号和一个表达式
定义:指定变量所占地址空间的长度
解释与思考
变量的声明都可以使用限定符进行限定,如: const、volatile等
const:
作用是指定的变量不能被修改.
经常谈及:指针常量、常量指针。
int * const p; 指针的指向不能变
const 修饰变量,类型是指针,因此称为指针常量。作用是指针的指向不能改变,但是指向的值可以改变
const int * p; 指针指向的值不能变
const 修饰类型,变量是 p,因此称为常量指针。作用是不能使用该指针修改变量的值,但是指针的指向可以改变.
volatile:
告诉编译器在每次使用该对象值时,都要重新读取它
———————————————————————————————
2.5 算数运算符
算术运算符:+ - * /(取整) %(取余)
———————————————————————————————
2.6 关系运算符与逻辑运算符
关系运算符:> >= < <= == !=
逻辑运算符:&& || !
———————————————————————————————
2.7 类型转换
———————————————————————————————
2.8 自增运算符与自减运算符
自增自减运算符: ++ --。
对于a++和++a类似的自增运算,效果都是将变量加 1 。
当作为前缀运算符时,表达式 ++n 先将 n 的值加 1 ,然后再使用 n 的值,
当作为后缀操作符是,表达式 n++ 是先使用变量 n 的值, 然后再将 n 的值 加 1。
解释与思考
对于一元二元三元运算符的区分是根据运算符结合操作数的个数决定的。
例:a++,++就是一元运算符,a+b,+就是二元运算符。
———————————————————————————————
2.9 按位运算符
位运算符: & | ^(异或) << >> ~
————————————————————————————
2.10 赋值运算符与表达式
赋值运算符: = += -= *= /= %=
————————————————————————————
2.11 条件表达式
三元运算符: ?:(expr1?expr2:expr3。
首先计算expr1,如果值不等于0(为真),则计算expr2,并以该值作为条件表达式的值,否则计算expr3的值,并以该值作为表达式的值,expr2和expr3只能有一个表达式被计算。
————————————————————————————
2.12 运算符优先级与求值次序
sizeof运算符:计算某种类型在内存中的长度。
逗号(,)运算符: 分割一对表达式按从左到右的顺序进行求值。
运算符有优先级之分,同一优先级,结合性相同。但是C语言没有指定同一运算符中多个操作数的计算顺序。例:
x = f()+ g();
f()可以在g()之前计算也可以在g()之后计算。因此如果函数f或者g改变了另一个函数所用的值,那么x的结果可能会依赖这两个 函数的计算顺序。为了保证特定的计算顺序,可以把中间结果保存在临时变量中
类似,C语言也没有指定函数各参数的求值顺序,例:
printf("%d %d\n", ++n, power(2, n));
在不同的编译器中可能会产生不同的结果,这取决于n的自增运算在power调用之前还是之后。如果想解决这种冲突,可以这样
++n;
&nbs