《征服C指针》读后笔记

1、不同数据类型的指针可以通过用void类型进行比较。

   例如:

   int i_a = 2;

   void *vo_t1,*vo_t2;

   double d_b = 1;

   vo_t1 = &i_a;

   vo_t2 = &d_b;

   if(vo_t1 == vo_t2)

printf("不同数据类型的指针可以通过用void类型进行比较!!\n");

else

printf("不同数据类型的指针可以通过用void类型进行比较!!\n");

2、不同数据类型的指针不能通过void来相互交换值。

3、不能使用NULL来作为字符串的结束。(NULL是指针)

4、可以“int *p=0;”,此时编译器把0当做一个NULL指针

       Because:

   #define NULL ((void*)0)

5、搞清楚:memset()函数,和calloc()函数的用法。

6、‘a’它的数据类型并不是char而是int

7*p+i)等于*i+p),也就是说p[i]等于i[p]

   例如:

   int a[10]={0};

    int *p;

    int i;

    for(i=0,p=a;i<10;i++)

    printf("%d ",p[i]);

    puts("");

    for(i=0,p=a;i<10;i++)

    printf("%d ",i[p]);

    puts("");

8、存在a[10];

   例如:

    for(i=0,p=a;i<10;i++)

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

    i++;

    printf("\n%d",i[p]);

9*p要比*(p+i)更高效

   例如:

   for(p=a;p<&a[10];p++)

    printf("%d ",*p);

    puts("");

   for(i=0,p=a;i<10;i++)

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

   Because*(p+i)每循环一次就要计算一次,

10、下标运算符[]和数组是没有关系的,[]只不过是为了人类写法方便,不需要写成*p+i, 这样的输入工作量会比较大

11C对数组的长度范围是不做检查的,所以当数组越界写入数据的时候,经常产生“内存被 破坏”的问题。

12、无论如何都要讲数组进行值传递的时候,建议将数组整体整理成结构体成员。

13、当数组出现在表达式中的时候,它会立刻解读成指针,也就是说原先的a[i]会被解读成*(a+i)

14、当今的操作系统都会给应用程序的每一个进程分配独立的“虚拟地址空间”,这是cpu和操 作系统系统工作的结果。所以就算我们毛手毛脚,糊里糊涂的制造了一个bug,破坏了某个 内存区域,顶多就是让当前的应用程序趴窝,但不会影响其它进程。

15、当然了,真正保存内存数据的还是物理内存。操作系统负责将物理内存分配给虚拟地址空 间,同时还对每一个内存区域设定“只读”或者“可读写”等属性

16、在如今的运行环境中,应用程序面对的是虚拟地址空间。

17、搞清fflush()函数,和sscanf()函数

18、全局变量可以在其他文件中使用,静态变量(static)只能在本程序中使用.

19、局部变量通常在它锁在的语句块结束的时候被释放,如果不想释放某个局部变量,可以在局部变量的前面加上static

20C语言变量除了作用域不同,还有存储期的差别。

21、静态变量:寿命从程序运行时开始,到程序关闭时结束。

22、自动变量:寿命到声明该变量的语句块被执行结束为止。(没有加static的局部变量,栈的机制)

23、通过malloc()分配的领域:寿命直到调用free()为止。

24、常量也是有地址的。

   例如:printf("%p %p",9,"abc");

25、自定义函数的自动变量(局部变量)分配了完全相同的内存地址

   例如:void func1(void)

   {

    int a;

    printf("%p......func1a\n",&a);

   

   }

   void func2(void)

   {

    int f;

    printf("%p......func2f\n",&f);

   

   }

   倘若每个函数里面同时增加变量:

   void func1(void)

   {

    int a,b,c;

    printf("%p......func1a\n",&a);

    printf("%p......func1b\n",&b);

    printf("%p......func1c\n",&c);

   }

   void func2(void)

   {

    int f,k,o;

    printf("%p......func2f\n",&f);

    printf("%p......func2k\n",&k);

    printf("%p......func2o\n",&o);

   }

   函数1和函数2的地址会一一对应。

27main()函数不同于上面。

28、函数和字符串常量在内存地址上存放的很近。它们汇总配置在只读内存区域的。

 

 

29、字符串常量相当于一个数组,

   例如:

   char *str="abc";

    printf("%s.....str",str);

    printf("%c.....str[0]",str[0]);

    printf("%c.....str[1]",str[1]);

    printf("%c.....str[2]",str[2]);

   是可以的。

30、函数可以在表达式中被解读成“指向函数的指针”,

   例如:

   Void func1(void)

   {

   Printf(%p   ,func1);

   }

31、表达式中的数组可以解读成“指向初始元素的指针”。

32、静态变量总是在虚拟地址空间上占有固定的区域。

33、自动变量的地址是在运行时被决定的。

34c语言通常将自动变量保存在栈中。

35、如果原型声明的函数中出现...,对于这部分的参数是不会做类型检查的。

   例如:

   void tiny_printf(char *format,...)

36assert.h头文件中有一个assert(表达式)函数,如果表达式为真,什么也不会发生,相反,就 会强制终止程序。

37、什么是stderr,srtbuf()

38、利用递归运算来快速排序,会有很高的效率。

39、可以利用宏来交换两个数的值,

   例如:

   #define SWAP(a,b){int t;t=a;a=b;b=t;}

   但是这些语句必须写在同一行上面,否则会出错。

40、自动变量前,如果加上一个static作为静态变量分配内存区域,就可以在程序的执行前被完 全初始化。

41、倘若一个字符串的长度是你不知道的,那么你可以定义为:char *ch_p;只要你定义成了指 针类型,那样也不会浪费内存空间。

   例如:

   char *ch_p;

    int len;

    printf("please input number:");

    scanf("%d",&len);

    ch_p=(char *)malloc(sizeof(char)*len);

    printf("please input %d character:",len);

    scanf("%s",ch_p);

    printf("%s\n",ch_p);

   但是这里会有很多疑问:当len的长度不够时,数据依然能够完好的保存,并且程序也能够正常的结束。不知道bug出现在哪里。

42malloc()函数是堆

43Malloc()大体的实现是,从操作系统一次性的取得比较大的内存,然后将这些内存“零 售”给应用程序。

44Malloc()函数的基本原理:

   1、最单纯的实现方式----通过链表实现:

   Malloc()遍历链表寻找到空的块,如果发现尺寸大小能够满足使用的块,就分割出来将其变成使用中的块,并且向应用程序返回紧邻管理区域的后面区域的地址。Free()将管理区域的标记改写成“空块”,顺便也将上下空块合并成一块。这样可以防止块的碎片化。

   如果不够大的空块(malloc()需要的大小),就请求操作系统对空间进行扩容(使用系统调用)。

   那么,在这种内存管理方式的运行环境下,一旦数组越界检查发生错误,越过malloc()分配的内存区域写入了数据,又会发生什么?

   此刻将会破坏下一个块的管理区域,所以从此以后的malloc()和free()调用中出现程序崩溃的几率会非常高(这并不是库(malloc)中的bug)。

   2、现实中的处理环境是不会这样单纯的实现malloc()的功能的。

   比如,作为内存管理方法,除了这里说明的链表方式以外,还有一个被大家熟知的“buddly block system”方法。这种将大的内存逐步对半分开的方式,虽然速度很快,但会造成内存的使用效率低下。

44malloc()绝对不是一个魔法函数。对于malloc()的动作原理,如果不是非常了解,就 很有可能陷入程序不能正常进行调试的窘境,或者常常写出非常低效的程序。

45、一般来说调用free()之后,对应的内存区域是不会立刻返还给操作系统的。

   仓促的调用free是有问题的,就算调用了free,指针B(指针A释放空间,B则还在继续用)引用的内存区域也不会立刻被破坏,暂时还保持着以前的值,直到在某个地方执行malloc,随着当前内存区域被重新分配,内容才开始被破坏。这样的bug,从原有产生到bug被发现之间周期比较长,因此给程序调试带来了很大困难。

46、我们无法直到当前指针指向的区域大小。

47C语言将虚拟地址直接交给了应用程序,库的一方是不能随意移动内存区域的。

48、指针不能直接赋常量,但是可以通过malloc先分配内存,然后再赋值常量。

49、自动变量重复使用内存区域,因此,自动变量的地址是不一定的。(现在就可以解释25 里为撒子不同函数中的自动变量地址会一一对应)。

50fprintf(stdin,””,...);=scanf(“”,...);

51fprintf(stdout,””,...)=printf(“”,...);

52、不管什么函数的自动变量,还有返回地址和值都是放在栈中,并且他们的距离不远,所以 一旦数据越界的话,很可能影响该函数的返回地址,更严重的是,还有可能改写其它函数 中的自动变量。而函数不是和它们放在一起的。

53、如果你调用了malloc(),就必须做返回值检查。

54、即使手工进行布局对其,也不能提高可移植性。

55、对于cpu来说采用小端字节序方式会更轻松。

56、一旦出现bug,就要带着“指针就是地址”的观点去解决它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值