<<Pointers on C(C和指针)>> 学习笔记

<<Pointers on C>> 学习笔记

1. 当你需要注释点一段代码时,用#if……#endif 比用注释要好;因为当用注释来从逻辑上删除一段代码,如果被删除的代码中有”/*”或”*/”字符讲或影响注释结果;(Pointers on C Page4)

2. C语言的四种基本数据类型:整型,浮点型,指针,聚合类型(数组和结构等)。(Page29

3. 字符常量的数据类型总是int;(Page31

4. 字符串常量(如:”HelloWorld”),在ANSI C标准中对字符串常量的修改行为的未定义的。它允许相同字符串常量存储于一个实体串,所以对字符串常量做修改时很危险的,因为这将会殃及程序的同他与此相同的常量值。(Page34

5. 应该使用typedef而不应该使用#define来创建一个新的类型名,因为后者无法正确处理指针类型。例如:#define def_pchar char *;

def_pchar a,b;在宏扩展后的b只是个字符型而非字符指针。(Page38

6. Int const  *pci; /*指向常整型的指针*/

   Int * const  cpi; /*指向整型的常型指针*/  

   说明:类似于const的修饰符遵循左结合优先的原则;(Page39

7ANSI C标准中 把函数形参的作用域设定为函数最外层的作用域(即为整个函数体)。(Page41

8. 数据的存储类型分为:普通内存,运行时堆栈,时间寄存器。(Page43

9. static: static关键用于修饰标示符的属性时,标示符的链接属性从external改为internal,但标示符的存储类型和作用域不受影响。即表明标示符为文件内访问。

        当static 用于代码块内部(“{ }”花括号中为代码块),static关键字用于修改变量的存储类型,即从自动变量修改为静态变量。(Page45

10. C语言中没有布尔类型,条件判定为整型代替,其规则为:

      零未假,任何非零值皆为真!!(Page78

11. 当定义结构体的时候必须注意内存对齐,比如:

struct struct_test

{

int  b;

char a[3];

};

struct struct_test

{

char a[3];

int  b;

};

Sizeof(struct_test)的值都是8.因为需要考虑内存对齐。(Page92

12. 注意:对指针进行间接访问(*p操作),必须对指针进行初始化。(Page12

13.一种比较好的函数定义风格:

类型

函数名( 形参列表 )

函数代码块

如:

Void

Function( void 

{

Do samething

}

因为这样的编程风格可以使我们在使用视觉或某些工具追踪代码时更容易找到函数名。(Page117

14. C 语言中数组并不完全等价于指针,比如:

指针和数组不等价情况举例:

int iArrary[10], *pi;

sizeof( iArrary ) == 40, sizeof( pi ) = 4 ; ( sizeof 操作符或单目操作符&的操作数为数组名时,sizeof(数组名)返回数组的长度,sizeof ( 指针)返回指针变量的字节宽度; &( 数组名 返回数组的首地址,而不是某个指针常量值的指针,而&( 指针 )返回指向该指针变量的指针 );(Page142

指针和数组等价情况举例:

int strlen( char *string );

int strlen( char string[] );

这两个指针等价只是当前上下文环境中,编译器会将string[]解析成一个指针。这样做只是为了让函数形参更直观,在这两个函数体内部执行sizeof( string ) 的返回值都是4,说明strng [] 被解析成了指针。(Page152

15. 当一个函数需要重复调用很多次,并且函数中有需要初始化的数组成员变量,此时每次调用都会对数组进行初始化,从效率上讲这个不值得。可以将数组申明成static 这样数组的初始化只需在程序的第一次运行时执行一次。(Page153

16. 区分两个不同的字符串初始化方式:

   char message1[] = “Hello”;

   char *message2 = “hello”;

其中char message1[] = “Hello”,等价于char message1[] = {‘H’,’e’,’l’,’l’’,’0’,’\0’};是一个数组的初始化,message1被申明为一个字符数组;而char *message2 = “hello”,是一个指针的初始化,message2此时为一个指针初始化指向一个常量字符串;(Page153

17.关于字符串的讨论:

库函数 strlen 的函数原型如下:

size_t strlen( char const  *string );

其中size_t 为函数的返回值类型,它在stddef.h被定义为一个无符号整型。而在表达式中使用无符号数可能导致不可预料的结果。举例如下:

If ( strlen( x ) >= strlen( y ) ) ……

If ( strlen( x ) – strlen( y ) >= 0 )……

但是事实上他们是不相等的。第一条语句执行正常。而第二条语句将会永远为真,strlen的结果是个无符号数,所以strlen( x ) – strlen( y ) 也是无符号数,而无符号数是永远 >0的。(Page176

18. 对于如下字符串处理函数:

char  *strncpy( char *dst, char const *src, size_t  len );

char  *strncat( char *dst, char const *src, size_t  len );

char  *strncmp( char *dst, char const *src, size_t  len );

如果strlen( src ) 的值小于len, dst数组就用额外的NULL字节填充len长度,如果strlen( src ) 大于或者等于len , 那么只有len个字符被原样复制到dst中。注意:他的结果将可能不会以NULL字节结束。 所以strncpy,strncat的调用结果可能不是一个字符串 。

处理办法如下:

char buffer[BSIZE];

…….

strncpy(buffer,someStr,BSIZE);

buffer[BSZIE - 1] = ‘\0’; (Page180)

 

19.  struct 

{

int a;

char b;

} x;

struct

{

int a;

char b;

} y[20] , *z;

这两个声明会被编译器当做两个截然不同的类型,即使他们的成员列表完全相同。因此,变量 和 与 的类型不同,所以, z = &x 是非法的。(Page196

 

20.void* malloc( size_t size ) 函数的一些讨论:

a.  malloc 的参数是以字节为单位的.

b.  malloc 所分配的是一块连续的内存。

c.  基于b,malloc调用有失败的可能,所以每次对malloc的返回指针都要进行NULL检测,这个很重要。(Page222

 

21. free( void * ); free 不能释放非堆内存。 同时free( p ); p 所指向的地址没有改变。在 必要的时候需要将p置空;free(p) ; p = NULL;( 学习心得 )

22. errno C语言中库函数执行过程中的错误代号,但是需要注意的是,只有当库函数失败时,errno 才会被设置。当函数成功运行时,errno 的值不会被修改。这个意味着我们不能通过测试errno 的值来判断是否有错误发生。反之,只有当被调用的函数提示有错误发生时检测errno 才有意义。(Page298

23. #include <stdlib> 标准库函数。其中的函数分为三类:算术,随机数,以及字符串转换。(Page327

24.结构体数据的内存对齐方式:当结构体的元素数据类型长度都小于处理器的位数时,以其中最长的最为内存对齐标准,如果结构体中的元素有比处理器位数大的,则以处理器位数为对齐单位。

25.volatile修饰函数的作用:

 在linuxsource codelinux/mm/memory.c)中有这样两句:

volatile void do_exit(long code); 
static inline volatile void oom(void) 

    printk("out of memory\n\r"); 
    do_exit(SIGSEGV); 
}

那么这里的volatile是什么意思呢?查了很多资料,都是说volatile对变量作用的结果,很少谈及对函数名修饰的作用。其实这里的作用是帮助编译器进行优化,而不是防止编译器优化,对应oom()do_exit()函数而言,它们是永远都不会返回的,如果还将调用它们的函数的返回地址保存在堆栈上的话,是没有任何意义的,但是加了volatile过后,就意味着这个函数不会返回,就相当于告诉编译器,我调用后是不用保存调用我的函数的返回地址的。这样就达到了优化的作用。这 种优化来源于GCC,在GCC2.5版本以后,使用noreturn属性来做优化,如void fatal () __attribute__ ((noreturn));,但是在Gcc2.5的版本以前,没有noreturn属性,所以就用volatile来表示不会返回的函数,以此达到优化的 效果。

 

posted on 2013-01-28 15:11  dougong  阅读(191)  评论(0编辑  收藏  举报

导航