分享

你必须知道的495个C语言问题 读书笔记

 千年长叹 2012-03-29

[置顶] 你必须知道的495个C语言问题 读书笔记

分类: C/C++ 64人阅读 评论(0) 收藏 举报

1.数值类型的选择:溢出特征重要而负值不重要,操作二进制位时避免符号扩展的问题,应该使用unsigned(无符号值)

char 8位 -127~127 最大值255

short int 和 int 均为 16位 -32767~32767 最大值65535

 

2.long long类型可以保证一个64位数

 

3.char *p1,p2;

这样声明p1是一个指向字符的指针,p2只是一个字符变量

声明两个指针 char *p1,*p2;

 

4.需要保证定义和声明的一致性,在.c文件中进行定义,在.h文件中进行声明,需要使用的时候,只要包含对应的头文件即可,定义变量的.c文件要包含该头文件

应该把全局变量的声明放到头文件,不要把外部函数的原型放到.c文件中

(ps:有关外部函数:在C里面,函数有效空间默认是extern,不用声明这意味着,平时写代码的时候如果某个函数仅仅是本文件使用记得在前面加 static,这是个习惯问题要有意识这样做其他文件要引用这个函数只需要提供函数原型就行了

写在.h文件里面,一般是一个模块一个.c和一个.h文件  .h文件包含所有外部需要看见的东西,不需要给外部看到的东西 全部加static,但编译的时候 要提供含有函数的.c文件)
5.typedef和define的区别
最好使用typedef,typedef在处理指针类型的时候能够正确处理,typedef的替换并不是完全基于文本的

  1. typedef char *String_t;  
  2. #define String_d *char;  
  3. String_t p1,p2;  
  4. String_d p3,p4;  

p1和p2均被声明为同样的char指针,而p3被声明为char指针,p4则被声明为char变量

 

另外一个例子

  1. typedef char *charp;  
  2. const charp p;  

这里p被声明成const,但不是p指向的字符,因为p的声明不会深入到typedef的内容来发现它涉及了指针

6.

  1. typedef struct {  
  2. char *item;  
  3. NODEPTR next;  
  4. }*NODERPTR;  

这段代码被声明报错,因为C语言需要向前声明,不能在定义typedef类型之前使用它

解决办法

  1. typedef struct node{  
  2. char *item;  
  3. struct node *next;  
  4. }*NODEPTR;  
  5. struct node;  
  6. typedef struct node *NODEPTR;  
  7. struct node{  
  8. char *item;  
  9. NODEPTR next;  
  10. }  
  11. struct node{  
  12. char *item;  
  13. struct node *next;  
  14. };  
  15. typedef struct node *NODEPTR;  

 

7.定义一对相互引用的结构体

  1. 方法一:  
  2. struct a{  
  3. int field;  
  4. struct b *bpointer;  
  5. };  
  6. struct b{  
  7. int field;  
  8. struct a *apointer;  
  9. };  
  10. typedef struct a *APTR;  
  11. typedef struct b *BPTR;  
  12. 方法二:  
  13. struct a;  
  14. struct b;  
  15. typedef struct a *APTR;  
  16. typedef struct b *BPTR;  
  17. struct a{  
  18. int field;  
  19. BPTR bpointer;  
  20. };  
  21. struct b{  
  22. int field;  
  23. APTR apointer;  
  24. };  

8.typedef int (*funcptr)();

定义了一个类型funcptr,表示一个指针,这个指针指向返回值为int的函数

  1. typedef int (*funcptr)();  
  2. funcptr fp1,fp2;  
  3. 等价于  
  4. int (*fp1)(),(*fp2)();  

 

9.char *(*(*a[N]) () ) ();

分析方法,由外至内

*(*(*a[N]) () ) () 是一个char型

(*(*a[N]) () ) ()char型指针

 *(*a[N]) () 返回char型指针的函数

(*a[N]) ()返回char型指针的函数指针

*a[N]返回char型指针的函数指针的函数

a返回char型指针的函数指针的函数的指针数组

 

另外的例子char *(*pfpc)();

*(*pfpc)() 是一个char

(*pfpc)()是一个指向char的指针

*Pfpc返回指向char指针的函数

pfpc指向返回char指针的函数的指针

 

10.有关数组:

数组和指针具有等价性,可以用指向malloc的指针分配的内存的指针来模拟数组,但是sizeof不能给出数组大小

 

关于动态分配多维数组:

  1. 方法一:  
  2. int **array1 = malloc(nrows * sizeof(int *));  
  3. for(i = 0;i < nrows; i++)  
  4. array1[i] = malloc(ncloums * sizeof(int *));  
  5. 方法二(如果要是动态分配的多维数组连续存储)  
  6. int **array1 = malloc(nrows * sizeof(int *));  
  7. array1[0] = malloc(nrows * ncloums * sizeof(int *));  
  8. for(i = 1; i < nrows; i++)  
  9. {  
  10.  array1[i] = array1[0] + i * ncloums;  
  11. }  

sizeof不能得到malloc内存块的大小,他只能得到指针的大小

动态分配数组大小后,继续改变他的大小可以使用realloc函数,如果重新分配成功,函数返回新的地址空间的指针

  1. int *newarray = (int *)realloc((void *)dynarray, 20 * sizeof(int));  
  2. if(newarray != NULL)  
  3. dynarray = newarray;  
  4. else  
  5.  return error;  

 

11.在一个文件中定义了一个数组,在另外一个文件中要获得这个数组的大小,不能使用sizeof,因为sizeof在编译时起作用,不能获得定义在另一个文件中的数组大小。

解决方法一:在头文件中定义一个常量

解决方法二:在数组的最后一位设置一个哨兵值

解决方法三:设置一个变量在文件一中储存变量大小,然后在文件二中调用这个变量来获得数组大小

 

12.void main不是正确的定义,main的返回值必须是int

只有以下两种定义方式是正确的: 
int main( void )
int main( int argc, char *argv[] ) 或者写成char ** argv
main 函数的返回值用于说明程序的退出状态。如果返回 0,则代表程序正常退出,否则代表程序异常退出。
13.没有显示初始化的变量,如果是static的静态存储类型的变量和函数外部什么的变量,系统会自动初始化为0,浮点型初始化为0.0
对于非静态类型的变量则为垃圾内容,未知
用malloc和realloc动态分配的内存也可能包含垃圾内容,需要使用者进行初始化,但是calloc动态分配的内存默认全部为0

 

14.char a[] = "Hello world!";

     char *p = "Hello world!";

当对p[i]赋值的时候会发生错误,因为如果不是在数组中指明字符的初始值,那么他会转化成一个无名的静态数组,导致不能被修改

char *p = "Hello world!"这个是一个字符串常量,可以像一个字符数组一样使用它,但是你不能更改这个字符串的值比如 a[2]='e'这样不行,
char a[] = "Hello world!"是一个字符串变量,可以被修改。
不过,这两者再作函数的形参的时候是完全等价的。
void function(char *pstr);
void function(char pstr[]);
可以相当绝对的说这两种完全等价,没有任何区别。

 

15.char a[3] = "abc";

这种写法是一种极限写法,虽然合法,但是不能使用strcpy和printf %s 因为他没有结束符'/0'

 

16.struct x1{...};

     typedef struct {..}x2;

区别,第一个声明了结构标签声明实例的时候需要写成 struct x1 a;,第二个声明了一个类型定义 声明实例的时候只需要写成 x2 b;

C和C++不同点是不能用结构标签自动生成类型定义名,在C++中第一个声明可以使用x1 a; 但是在C中就必须加上struct,或者就直接用第二种方法typedef,那么声明成一个类型定义,就可以直接使用x1 a;

 

17.任何一个malloc调用都要对应一个free释放内存

 

18.不能用== 和 !=来比较结构

 

19.向接受结构的函数中传入常量值

plotpoint((struct point){1,2});

传入了一个结构常量

 

20.2字节的short int变量必须存储在偶地址上,4字节的long int变量必须存储在4的整数倍地址上,要求所有数据必须对齐

在struct {

char a;

int b;

}

结构标签中,a和b中间会留下一个空洞,以确定int对齐

所以数据成员应该按照元素类型大小进行排列,而不是按照数组大小进行排列

 

21.sizeof有可能返回大于结构大小的期望值,因为为了保证结构数组的对齐有可能在尾部有填充的空洞

 

22.struct和union(联合)的区别是union是一个成员的相互重叠的结构,某一时刻只能使用一个成员,联合的大小是他最大成员的大小,union只有第一个成员可以被初始化

 

23.枚举enum和使用一组define的区别:区别很小

标准中允许枚举和其它整形类别自由混用而不会出错。 枚举的一些优点: 自动赋值(只要给第一个数赋值以后就依次加1); 调试器在检验枚举变量时, 可以显示符号值; 它们服从数据块作用域规则。

 

24.结构声明中的位域

struct record{

char *name;

int refcount : 4;

unsigned dirty : 1;

};

后面的数字表示该域用位计量的准确大小

 

25.有关i++的表达式

(1)引入了序列点的概念:两个序列点之间一个对象最多只能被修改一次,而且只有在确定将要保存的值的时候才能访问前一个值

引入新序列点的操作符:&&,||,?:,逗号操作符处

a[i] = i++;这个式子会导致未定义行为,因为这里i没有被确定保存,无法判断a[i]中的i是新值还是旧值,它被修改了两次

(2)后缀的++和--只有在输出其旧值才进行自增和自减运算

所以

i = 5;

printf("%d",i++*i++);

得到的结果是25,最后i的值是7

 

 

26.不用临时变量就交换两个数的值

利用异或操作符

int a = 2; int b = 4;

a ^= b ^= a ^= b;

 

27.使用操作符的优先级来控制计算顺序是无效的

f() + g() * h();

程序不会按照操作符的顺序运行g() h() f();

同样道理用到(i++) * (i++);

一个特殊的情况是使用&& ||,这两个操作符会引出一个额外的序列点,对后面的操作进行短路

常用这个性质来检测操作是否安全

if(d!=0 && n/d)        短路掉了d等于0的情况

{...}

if(p!=NULL || *p == '/0')    如果p是空指针,对p进行赋值会导致程序崩溃

{...}

 

28. 

 C++中应该优先使用++i;

因为效率更高

 

29.int a = 1000; int b = 1000;

long int c = a * b;

这个表达式的问题在a*b是按照int型运算的,返回给c的右值可能是a*b溢出或者被截断后转换成long型的值

正确的写法是

int a = 1000; int b = 1000;

long int c = (long int )a * (long int )b;

 

30.double degC, degF;

   degC = 5/9*(degF-32);

输出的值是0,因为5/9被当做int形运算(二元操作符的两个操作符都是整数,则进行整数运算)

可行的方法是

degC = (double)5/9*(degF-32);

或 degC = 5.0/9*(degF-32);

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多