有段事件没有写C程序了,有些地方有些生疏了。这两天事情比较少,准备再系统的看一边C的基础知识。这里再总结一下平时没太注意的知识要点。 1、C语言的语句块 在C语言中,任何允许出现语句的地方既可以是由;号结尾的一条语句,也可以是由{}括起来的若干条语句或声明组成的语句块(Statement Block),语句块和上一章介绍的函数体的语法相同。注意语句块的}后面不需要加;号。如果}后面加了;号,则这个;号本身又是一条新的语句了,在C语言中一个单独的;号表示一条空语句(Null Statement)。
6 int main(void) 7 { 8 printf("hello\n"); 9 {}; //这里相当于两个空语句了 10 11 int i= 0; 12 { 13 int i = 1; 14 int j = 2; //每次进入语句块时为变量<code>j</code>分配存储空间,每次退出语句块时释放变量<code>j</code>的存储空间。 15 printf("i=%d, j=%d\n",i,j); 16 } 17 printf("i=%d\n", i); //can't access j here 22 return 0; 23 }
2、取模运算%
C99规定,如果a
和b
是整型,b
不等于0,则表达式(a/b)*b+a%b
的值总是等于a。
结合整数除法运算要Truncate Toward Zero,可以得到一个结论:%运算符的结果总是与被除数同号(想一想为什么)。其它编程语言对取模运算的规定各不相同,也有规定结果和除数同号的,也有不做明确规定的。
写一个函数,参数是整型变量x,功能是打印x的个位和十位:
25 void quwei(int x) 26 { 27 int tmp; 28 29 tmp = x%10; 30 printf("个位数为:%d\n",tmp); 31 32 tmp = (x%100)/10; 33 printf("十位数为:%d\n", tmp); 34 }
3、float和double类型
7 int main() 8 { 9 float x = 0; //当x定义为double时候出错,问题如何解决 10 printf("input x:\n"); 11 12 scanf("%f", &x); 13 14 printf("the x is:%f\n", x); 15 printf("the ceil:%f\n", ceil(x)); 16 printf("the floor:%f\n", floor(x)); 17 18 // printf("the result is:%f\n", myround(x)); 19 20 return 0; 21 }
问题发现:当x定义为double类型时,上面程序错误,x读取的值有误。但是编译时需要加上-Wall选项才能发现原来是类型不匹配。
如何读取double类型变量?
4、结构体的初始化
5 int main() 6 { 7 //定义复数 8 struct temp 9 { 10 double real; 11 double img; 12 }; 13 14 double x = 2.0; 15 //初始化复数 16 struct temp z1 = {x,3.0};//z1.real=2.0, z1.img=3.0 17 struct temp z2 = {3.0,};//z2.real=3.0, z2.img=0.0 18 struct temp z3 = {0};//z3.real=0.0, z3.img=0.0 19 20 return 0; 21 }
注意:z1
必须是局部变量才能用另一个变量x
的值来初始化它的成员,如果是全局变量就只能用常量表达式来初始化。这也是C99的新特性,C89只允许在{}中使用常量表达式来初始化,无论是初始化全局变量还是局部变量。
{}这种语法不能用于结构体的赋值,例如这样是错误的:
20 struct temp z1; 21 z1 = {3.0, 4.0};
以前我们初始化基本类型的变量所使用的Initializer都是表达式,表达式当然也可以用来赋值,但现在这种由{}括起来的Initializer并不是表达式,所以不能用来赋值。
有些时候结构体或数组中只有某一个或某几个成员需要初始化,其它成员都用0初始化即可,用Designated Initializer语法可以针对每个成员做初始化(Memberwise Initialization),很方便。Designated Initializer是C99引入的新特性,用于初始化稀疏(Sparse)结构体和稀疏数组很方便。例如:
struct temp z1 = { .y = 4.0 };
结构体变量之间使用赋值运算符是允许的,用一个结构体变量初始化另一个结构体变量也是允许的,例如:
struct complex_struct z1 = { 3.0, 4.0 }; struct complex_struct z2 = z1; z1 = z2;
同样地,z2
必须是局部变量才能用变量z1
的值来初始化。既然结构体变量之间可以相互赋值和初始化,也就可以当作函数的参数和返回值来传递。
struct temp add_complex(struct temp z1, struct temp z2) { z1.x = z1.x + z2.x; z1.y =z1.y + z2.y; return z1; }
由.运算符组成的表达式能不能做左值取决于.运算符左边的表达式能不能做左值。在上面的例子中,z
是一个变量,可以做左值,因此表达式z.x
也可以做左值,但表达式add_complex(z, z).x
只能做右值而不能做左值,因为表达式add_complex(z, z)
不能做左值。
5、枚举
4 int main() 5 { 6 enum my_type {RED, YELLOW}; 7 int RED = 1; 8 printf("%d\t%d\n",RED, YELLOW); 9 10 return 0; 11 }
结构体的成员名和变量名不在同一命名空间中,但枚举的成员名却和变量名在同一命名空间中,所以会出现命名冲突。以上代码是不合法的:
本文参考《Linux C编程 一站式学习》