c语言基础总结_c语言知识基础总结
c语言基础总结由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“c语言知识基础总结”。
常见错误
1.使用未初始化和未赋值的变量
描述:非全局变量和静态变量在定义时不自动进行初始化,初值为一个与该程序运行环境有关的随机数。不赋值或没有显示初值就直接使用这样的变量是错误的。
解决:所有变量都显示地进行初始化,建议数值变量初始化为0,指针变量初始化为NULL
2.不考虑数值溢出的可能
描述:当赋值超过此范围数值,就会产生数值溢出,得到不正确的值。
解决:预先估算运行结果的可能范围,采用可能范围更大的,不处理负数,就用无符号类型。运算还没开始前,判断运算数是否在合理取值的范围内,超出则停止运算。采用第三方无取值范围的运算库。
3.不用sizeof()获得类型或变量的字长
描述:相同类型在不同平台上占得字节数不同。Int在16位,32位,64位系统分别占2,4,8个字节。结构体所占字节也不是所有成员字长的简单相加,而是和平台与编译器,编译项都有关系。
解决:用且只用sizeof获得字长
Intwriteint(intfh ,inti)
{
Returnwrite(fh ,&i,sizeof(i));
}
4.假定类型的取值范围
描述:类型的取值范围与程序编译息息相关。
解决:使用limits.h和float.h定义的宏(INT--MAX,INT----MINULONG--MAXFLT---MAX
5.期望两个整数的运算自动获得浮点数的结果
描述:两个数运算的结果还是整数,不是浮点数
方案:强制转换为浮点数,再运算
例:voidfunc(void)voidfunc(void)
{{
Floatf=0.0;floatf=0.0;
Inta =3,b=2;int a=3,b=2;
f=a/b;f=a/(float)b;
printf(“%f,f);printf
}
6.不预先判除除数是否为0
编译器反应:直接写入inti=100/0,编译器会报错,编译器对此问题沉默
解决方案:先判断除数是否为0,若是0则不运算。
7.混淆“&,|”与“&&,||”
说明:他们是两种不同的运算符,有人总是弄错
8使用依赖编译器求值顺序的语句
描述:printf(“%d,%d,%d,i++,i++,i++);i=0可能输出 0.1.20.0.0.2.1.0方案:按期望的顺序分别求职,再综合运算
Voidfunc(void)
{
Int a,b,c ,i=0;
a=i++;
b=i++
C=i++
Printf(“%d,%d,%d”,a,b,c)
9.使用依靠算符优先级的表达式
描述;没有记住优先级,容易出错。
解决:用括号明确优先计算的部分
10.表达式过于复杂
描述:(a>b||b>c)&&(o>P||q>p)?(a-b)*c+(o-p)*q:(a*b*c)-(o*p*q)
11.用“==”时误用“=”
12.用“==”比较两个浮点数
描述;两个数值表面相等或者非常接近的浮点时用“==”比较,结果可能不同
解决;不用float用double在精度运算中两个浮点数的差的绝对值只要小于一个
精度范围,就可以相等
13.使用幻数
描述:直接使用的常数
解决;把幻数定义为宏或枚举,建议使用枚举。编译提示会更清晰,准确
#definearray-srze10
Enum(array-size=10)printf()和scanf()中格式控制字符串与参数类型不匹配
15.循环或判断语句以“;”结尾
描述:分别表示循环和判断语句的终结,后面的代码不算循环体或分支,而是循环和判断
平行的代码
解决:禁止在循环判断语句末尾出现分号,循环体为空的情况下,While(.........)
{
}
16.在循环体内改变循环结束条件
例如:voidfunc(void)
{
Int a,end:
-------
While(a
{
在这里修改end的值
}
}
17.case分支不用break结束
规定每个case分支必须用break结束,两个分支用同样的代码,就把代码定义为函数
基本概念
函数是c的基本单位,必须有且仅有一个main函数。一个c可以包含一个到多个函数,在函数中可以调用系统提供的库函数
函数首部:函数返回值类型,函数名,形参类型,形参名的说明
函数
函数体:大括号中的内容,包括变量声明(对象)语句和执行(动作)语句c程序书写规则;以分号结束,并且书写注释;“/**/,注释之间不能留有空格常见关键字:asmautobreakcasecdeclchar
Constcontinuedefaultdodoubleelse
Enumexternfarfloatforgoto
Hugeifinterruptintlongnear
Pascalregisterreturnshortsigned
Sizeofstaticstructswitchtypedef
Unionunsignedvoidvolatilewhile
标识符:系统自定义标识符,用户自定义标识符
运算符:算数运算符:+—*/%关系运算符: >>==
逻辑运算符:!&&||
赋值运算符:=
复合的赋值运算符:+=-=*=/=%=&=!=^==
增一减一的运算符:++--
条件运算符:?:
强制类型转换运算符:
指针和地址运算符:*&
计算字节数运算符:sizeof
下标运算符:[]
结构体成员运算符:->
位运算符:>|^&~
逗号运算符:,分隔符:相邻保留字,标识符之间由空格或回车换行做分隔符:相邻同类项之间用逗号分隔
声明相同类型的变量之间可用逗号分离,向屏幕输出的变量中各变量表达式之间用
逗号分离。
常见的转义字符:n 换行r回车(不换行) 字符串结束t 水平制表
v 垂直制表b退格f走纸换页a响铃报警
” 双引号’单引号 一个反斜线?问号
常见错误
数组;数组的下标都是从0开始的,访问时发生下标多1或者少1都会越界访问内存错误
用变量来定义数组长度会导致语法错误,应该用整型常量或整型常量表达式定义
用a[x,y]而不是a[x][y]的形式来访问二维数组中的元素,将导致语法错误
(数组的第1个元素的下标是0,数组元素1是指数组元素的下标为1,是数组的第二个元素)
忘记对需要进行初始化的元素初始化,导致运行结果错误
对数组初始化的过程中,提供的初值个数多于数组所能容纳的元素个数定义字符数组长度时,必须要多留一个字节的存储单元,存放结束标志 打印一个不包括字符串结束标志的 ,导致运行结果错误
直接使用赋值运算符对字符串赋值是错误的,必须用strcpy()赋值
直接使用关系运算符比较字符串大小是错误的,必须使用strcpy()比较
字符串必须使用双引号括起来,单引号括起来是错误的。
一对双引号将一个字符常量括起来,产生一个指向包含两个字符的字符串指针(把字符当做实参去调用形参是字符串的函数;把字符串当做实参去调用形参是字符的函数,都会导致语法的错误!)
误以为在函数中定义的静态局部数组元素中的元素,在每次函数调用时都初始化0(函数原型,函数定义的头部和函数调用语句三者,在形参和实参的数量,类型和顺序,以及返回值的类型上没有严格保持一致,将导致语法错误。)
指针:误以为用来声明指针变量的星号(*)会对同一个声明语句中的所有指针变量都起作用,而省略了其他指针变量名前的星号。实质是每一个每一个变量名前的星号都不能省略。
没有对指针变量进行初始化,或没有将指针变量指向内存中某一个确定存储单元的情况下,就利用这个指针变量去访问它所指向的存储单元,将导致严重的运行错误。没有意识到某些函数形参是属于“传地址掉调用”而数值不是指针当做实参赋值给这形参。
对没有指向数组中的某个元素的指针变量进行算数运算,是无意义的。
对并非指向同一数组中元素的两个指针进行相减或比较运算。是无意义的。每个数组都有上,下边界,指针超出了边界就会造成越界访问内存错误。
除非两个指针类型都是void,否则将一种类型的指针赋值给其他类型的指针,造成语法错误。
试图用一个void的指针变量去访问内存,是一个语法错误。
试图以指针运算的方式来改写一个数组名所代表的地址,是一个语法错误
内存分配不成功的话会导致非法内存访问错误,只要运行前检查指针是否为空指针,可以避免错误发生。
如果内存分配成功,但是没有初始化,将会导致非法内存访问错误。
向系统申请了一块内存,结束后忘了释放内存,造成内存泄露。
释放了内存,但却仍然使用,会产生“野指针”
结构体,共用体:定义一个结构体时,忘记最后加上一个分号,导致语法错误
将一种类型的结构体赋值给另一种类型的结构体,导致语法错误
对两个结构体或者共用体进行比较,导致语法错误
在结构体指向运算符的两个组成符号“-” 和“>”之间插了空格,或者写成“→”导致语法错误
只使用成员变量名访问结构体的一个成员,导致语法错误
直接使用结构体的每个成员类型所占内存字节数的“和”作为一个结构体实际所占的字节数。是错误的。
没有标明结构体数组下标 就访问其中一个结构体数组元素,导致语法错误。
函数
递归函数是需要返回值的,在递归函数中忘记返回数值,是错误的忘记了编写递归终止条件的分支语句,写错了递归步骤,都会导致递归函数不能收敛到递归的终止条件,引起无穷递归
定义函数指针时,忘记将函数指针变量名及前面的星号用圆括号括起来,使得本应声明函数指针变量的变量声明变成了一个函数声明语句。
将函数指针作为函数参数时,不在函数指针变量名后的一对圆括号中列出各函数参数的类型,导致编译错误。
实施细则
1.函数
1.函数指针:通式:数据类型(*指针名)()int(*p)()
错误:忘记前一个()意义是声明一个函数,函数名为P,返回值是一个指向整型变量的指针
忘记了后一个(),意义是定义了一个指向整型变量指针。使用:1.定义过程 2.函数指针赋值过程3.调用过程
2.递归:一个对象部分地由它和自己组成或它自己定义,称它是递归的。
3.返回指针值的函数:通式:数据类型*函数名(参数名){}
区别;不带*的函数值,函数值只能是一个数据,不能是一组带*的函数值,不仅是一个数据,还能是一组数据。
2.结构体,共用体
位段:指定了存储位数的结构体或共用体的成员叫位段
优点:用最少的位数存储数据注意:必须声明为int或unsigned型使用:用struct作为关键字,定义了unsigned 的三个位段
“:”代表位段宽度的整数常量,访问位段成员的方法与访问结构体成员的方法基本一致,用“圆点运算符”或“箭头运算符”
共用体:将不同的数据类型组合在一起,共占有同一段内存的用户自定义数据类型注意:必须有足够大的内存空间将占据最大内存空间的成员存储在内,内存空间的大小由占据内存空间成员所占的空间数决定。
动态数据结构:在结构体类型中,如果包含了本结构体类型的成员,由于本结构所占的内存字节数无法确定,系统无法正常分配内存。
声明结构体类型是不能包含自我,但可以包含指向本结构体类型的指针域。操作:
Structtemp
{
Intdata;
Structtemp*temp;
};
利用函数malloc()申请一个结构体的内存
Structtemp
{
Intdata;
Charname[10];
};
Structtemp *p;
P=(struct temp*)malloc(10*sizeof(structtemp));利用函数calloc()申请一个结构体内存
Structtemp *p
P=(struttemp*)calloc(10*sizeof(struct 利用函数free()释放申请的内存空间,链表的定义
temp));