真正深入学习C语言已经3年有余了。不过还是有很多知识点没有记下来,在此总结一下,也帮助C语言新手度过新手难关。
如果你已经认真阅读过谭浩强C,那么复习如下知识大约需要1个小时,而且保证包括大部分易错知识点:)
本篇是《帮你度过C语言新手阶段》系列的第二篇。
第二十关:
定义函数时,有传统方式和现代方式。
现代方式:
int max(int x,int y){
…
}
传统方式:
int max(x,y)
int x;
int y;
{
…
}
第二十一关:
函数的定义和声明不是一回事。
定义是对函数功能的确立,包括指定函数名、函数值类型、形参以及其类型、函数体等,它是一个完整的、独立的函数单位。
声明的作用是把函数的名字、函数的类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。
在函数的声明中完全可以不写形参名,而只写形参的类型。如:float add(float,float);
旧版本的C语言中,函数声明可以只声明函数名和函数返回类型,如int add();
如果在函数调用之前,没有对函数做声明,则编译系统会把第一次遇到的该函数形式作为函数的声明,并将函数返回类型默认为int。所以如下的程序,虽然没有事先声明max函数,但仍可以侥幸通过:
int main()
{
int c=max(2,5);
}
max(int x,int y)
{
int z;
z=x>y?x:y;
return z;
}
可见,没有定义函数类型(即函数返回类型)的函数,都会默认为int型。
上述程序能侥幸通过的原因是return z中的z是int型。如果z是其他任何类型,程序都会报错,即使是相兼容的short、long、char或unsigned int都不行!
第二十二关:
形参数组可以不指定大小,且在形参中int a[]和int a[131212]和int *a是等价的!
形参多维数组的话,只能省略第一维的数组,其他维必须按照正确的值来填写。
第二十三关:
用户存储空间包括:
(1)程序区
(2)静态存储区
(3)动态存储区
全局变量全部放在静态存储区。
动态存储区存放以下数据:
1 函数形参
2 自动变量,即未使用static声明的局部变量
3 函数调用的现场保存和返回地址
在C语言中,每个变量有两个属性:
1 数据类型
2 数据存储类型
第二十四关:
函数中的局部变量,如果不专门声明为static存储类型,则默认都为auto存储类别,都会被分配到动态存储区。auto是一个默认关键字。即int a;等价于auto int a;
静态存储类别的变量,被分配在静态存储区,在程序整个运行期间都不释放。静态局部变量在编译时赋初值,且只赋初值一次,如果用户不指定,则为0。(auto类型变量的话,如果用户不指定初值,则初值是一个不确定的值)
第二十五关:
为了提高效率,C语言允许将局部变量放在CPU中的寄存器里,这种变量叫做“寄存器变量”,如register int a;
只有局部自动变量和形参变量可以作为寄存器变量。
局部静态变量不能作为寄存器变量。
第二十六关:
extern用于声明外部变量,如extern char a,b;
注意,除非引用的外部变量是int型,否则必须写上数据类型,而且和外部变量的数据类型必须完全一致。
第二十七关:
使用#define定义的宏,可以用#undef来取消。
如#define G 9.8,可以用如下命令取消:
#undef G
C程序中,用双引号括起来的部分,不会被宏所代替。
定义计算圆面积的宏,应该注意要加上括号,即:
#define PI 3.14
#define S(r) PI*(r)*(r)
宏名是无类型的,而且它的参数也是没有类型的。
宏替换不占运行时间,只占编译时间。
第二十八关:
头文件,使用.h后缀只是为了表明文件性质。所以,即使没有.h也是没问题的。
头文件里应该可以函数原型、宏定义、结构体类型定义以及全局变量定义。
第二十九关:
&和*的优先级相同,且结合性是自右至左。(单目运算符的结合性是右结合)
*pointer++,由于++和*为同一优先级,而结合性又是自右至左,所以相当与*(pointer++)
第三十关:
使用指针来引用数组,可以提高目标程序质量(占内存少,运行速度快)。
main()
{
int a[10];
int *p,i;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
printf(“\n”);
for(p=a;p<(a+10);p++)
printf(“%d”,*p);
}
此程序会提高程序运行效率,因为像p++这样的指针操作是比较快的。
数据名是数组首元素的地址,它是一个指针常量。它的值在程序运行期间是不变的。
第三十一关:
当在形参中要引用一个数组时,往往C语言专业人员喜欢用指针变量做形参。如,专业人员
更喜欢f(int *arr,int n);
不太喜欢f(int arr[], int n);
第三十二关:
对于int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
a[0],a[1],a[2],每一个元素又是一个一维数组。
a+1代表第一行的首地址,而a+1就代表第二行的首地址。
*(a[i]+j)和*(*(a+i)+j)是二维数组元素a[i][j]的值。
a和a[0]的值虽然相同,但其指针类型不同,a指向一维数组,a[0]指向a[0][0].
第三十三关:
int (*p)[4],p是一个指针变量,它指向包含4个整型元素的一维数组。注意*p两侧的括号不能缺少,因为[]的优先级高于*,所以如果写成*p[4],那就变成了*(p[4]),这个表示一个含有4个元素的一维数组,其中每个元素都是一个指针变量。
第三十四关:
用字符指针做形参来实现字符串的复制:
void copy_string(char *from, char *to)
{
for(;*from!=’\0′;from++,to++) *to=*from;
*to=’\0′;
}
此代码可以改进为:
void copy_string(char *from,char *to)
{
while((*to++=*from++)!=’\0′);
}
此代码还可以改进,由于’\0′可以用0代替,且条件里0即代表假,所以代码可修改为:
void copy_string(char *from,char *to)
{
while(*to++=*from++);
}
对于C语言熟练之后,这种形式的使用是非常多的,读者应该逐渐熟悉它,掌握它。
over~
通过RSS订阅
October 25th, 2008 at 10:11 pm
#define S(r) PI*(r)*(r)
还是不对的,至少要这样:
#define S(r) (PI*(r)*(r))
回复