您的位置:首页 > 编程语言 > C语言/C++

C语言总结-个人学习笔记

2008-03-11 00:16 597 查看
C语言总结

l         对浮点类型数据的处理
1.         进行大小比较:直接比较可能产生不精确现象,可用极限思想,fabs( a – b ) < ε,但要小心处理好精度,因为当数字很大时可能会很不精确。
2.         强制类型转换不等同于取整数部分。因为不同数据类型存储的字节数不同,截取前面字节的内容不一定就是整数部分。
 

l         初始化问题
1.         重复输入处理多组数据,注意每次循环体开头要初始化。
2.         计数器的初始化,0还是1?
3.         对指针解参考之前要先初始化。
 

l         Switch语句的标签值要求是常量整数。
l         else与最近的if结合。
l         “/”运算符操作数是int时,结果“向零取整”。
l         getchar()记得处理换行符。
 

l         数组与指针
1.         使用数组一定要注意不要越界。数组的越界访问会不确定地修改某些变量值,造成的错误很难预计和检查。
2.         指针:4种
4000
类型、指针运算(连续内存)、函数指针
3.         关于链表:
每次修改指针,都要仔细想想:链表是不是在这里断了?
4.         经典例题:
int a[5]={1,2,3,4,5};

int* p=(int*)(&a + 1);

printf("%d/n",*(p-1));
问:输出结果。  5
因为:
&a + 1:
(int)a + sizeof ( int [5] ) * 1;
p - 1:
(int)p - sizeof( int );

 



 



 



 



 



 

a是数组名,不是指针,数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。

 

&a 的类型是 int (*)[5]
其实就相当于一维数组指针(基础的C语言教程上都有讲)
&a + 1
就是 a + sizeof(a)
通俗的说,这个1代表整行的数组空间
(罗嗦一句:其实a作为数组名,可以看作指向该数组第一个元素的指针,数组名毕竟不是指针,它们之间有区别,只是在某些情况下可以把数组名看作指针。而且,a不能进行a++等这样的运算,它只可看作常指针。)

 

地址是相同的,即都是“数组首地址”(这已经是老生常谈了,究其原因是编译器“捣的鬼”,因为编译器知道a是一个数组名,所以它故意让&a返回与a相同的地址值。如果你不相信的话,可以打印出来看看)。
但是,尽管"a"和"&a"代表相同的地址,我们仍然不能用“int *p = &a;”代替“int *p = a;”,因为&a的类型是“int (*)[4]”,而不存在任何隐式转换能够将“int (*)[4]”转换为“int*”,所以前者是非法的;而后者是众所周知的“数组退化为指针”行为,是合法的(尽管这种“退化行为”有时候很危险.

摘自www.csdn.net

 

l         存储类型
1.         静态局部变量:第一次进入函数体初始化(如果有),修改后的值对下一次进入循环体可用。非静态缺省初始化初值将不确定;静态默认为0。生存期→全局(只创建一次)
2.         静态全局变量:非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。作用域→本文件
3.         寄存器变量:变量存放在CPU的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写, 这样可提高效率。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。只有局部自动变量和形式参数才可以定义为寄存器变量。因为寄存器变量属于动态存储方式。凡需要采用静态存储方式的量不能定义为寄存器变量。在Turbo C,MS C等微机上使用的C语言中, 实际上是把寄存器变量当成自动变量处理的。

4.         外部参数(如全局变量)默认是extern类型。

 

l         作用域的一个致命易错点

函数中声明的变量,在退出函数时就被释放了,如果返回的是指向该内存位置的指针,很危险啊。

(1)指针消亡了,并不表示它所指的内存会被自动释放。

(2)内存被释放了,并不表示指针会消亡或者成了NULL指针。

经典例题:

#include   <stdio.h>
#include   <stdlib.h>
#include   <string.h>
#include   <malloc.h>
#include   <math.h>

char *test(void)
{   char   str[80]   =   "1234567 ";
    char   *resu   =   str;

    return   resu;
}

int   main(void)
{   char   *pstr;

    pstr   =   test();
    puts(pstr);

    return   0;
}

str[80]由于它申请的内存在堆栈区,所以在函数调用完毕后它申请的内存空间会自动释放,所以main函数中调用返回的指针指向的一块已经释放的内存,既数据已不存在,所以才会出现问题。
修改成char* str =  (char*)malloc(80); 动态申请内存就可以了。
 

l         字符串
1.         用字符数组
2.         小心越界,很多函数都不能追加’/0’。
 

l         良好的编程习惯
1.         使用库函数一定要记得用#include预处理指令,把调用的库函数头文件包含在程序中。
2.         scanf语句一定要记得取地址符&。
3.         写完程序检查所以的“=”和“==”。
 

l         结构与联合
1.         声明里面不能初始化。因为结构声明了,才会有系统分配的一块内存空间。
2.         内存对齐问题
3.         对于结构体数组,用法与普通数组类似。
4.         参见《内存分配函数总结》。http://www.yueluo.net/C/20070825/1408.html
 

l         格式化输入输出
1.         scanf()函数执行成功时的返回值是成功读取的变量数,也就是说,你这个scanf()函数有几个变量,如果scanf()函数全部正常读取,它就返回几。但这里还要注意另一个问题,如果输入了非法数据,键盘缓冲区就可能还个有残余信息问题。可用fflush(stdin);清空,
参见《scanf()总结》。

2.         Turbo   C(TC)系统的浮点连接错误  
用TC-2.0系统编写小的C程序,如果程序里用到浮点输入,有时运行中会出现下面错误信息:  

scanf   :   floating   point   formats   not   linked  
Abnormal   program   termination  

这个错误信息的意思是:scanf的浮点格式转换程序没有连接。  

TC开发时(80年代)DOS下的存储资源紧缺,因此TC在编译时尽量不加入无关部分。在没发现需要做浮点转换时,就不将这个部分安装到可执行程序里。但有时TC不能正确识别实际确实需要浮点转换,因此就会出现上面错误。  

解决方法:设法告诉TC需要做浮点数输入转换。例如,可增加了一个double变量并用它输入。
     大程序里由于变量很多,只要有了线索,TC就会把浮点转换连上,因此反而不常遇到这个问题。  
3.         scanf规则
     如果输入流的内容多于   20   个字符,则下次   scanf()   从此次停止处开始读入。若达到最大域宽前已遇到空白符,则对该域的读立即停止;此时,scanf()   跳到下一个域。

     所以,如果要对读入的数据进行判断,小心因为不匹配而造成错误。
 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息