C和指针读书笔记_第1页
C和指针读书笔记_第2页
C和指针读书笔记_第3页
C和指针读书笔记_第4页
C和指针读书笔记_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、1.scanf()的返回值是函数成功转换并存储于参数中值的个数!2./*scanf 不会读取该行中最后一个它不需要读取的值换行符'n',所以该行中的剩余部分就会留在那里等待被读取。这个换行符或者其他scanf不想读取的字符就会被解释成下一行的开始数据。所以用下面这种方法来读取并丢弃这些剩余字符。*/int ch;  /*EOF在stdio.h中定义为int,所以为了防止ch = EOF将int强转为char,也将ch声明成int型*/while(ch = getchar() != EOF && ch != 'n') 

2、3.注意事项:避免越界访问数组*在使用下标前先检查它们的值;(如果下标是由在键盘由用户输入的,要加上后面code)int array = 0,1,2;scanf("%d", &i);if(i < sizeof(array) arrayi; /这样再引用以i为下标的数组;*在while or if 表达式中蕴含的赋值操作;(在fork一个进程时要小心用这种技巧,不要 偷懒,在while of if 前就先将fork的返回值赋值操作。)*始终要进行检查,确保数组不越界;4.strlen()的个数不包含'0'5.可以把字

3、符串常量赋给一个指向字符的指针,这个指针指向这些字符所存储的地址。 但是,你不能把字符串常量赋给一个字符数组,因为字符串常量的直接值是一个指针,而不是字符本身。strcpy(char *des_ptr, const char *src_ptr) /段错误,对指针变量赋了一个字符,而不是一个地址(指针变量)。 des_ptr = src_ptr; /right,但是只是在内存中只有一段字符串,只是二个指针都指向了这个字符串常量,不是在内存中的一个新的地址空间复制了一段src_ptr的字符串。 strcpy(char des_ptr, const char *src_ptr)/

4、*/src_ptr = strchr(src_ptr, 'a');strcpy(char des_ptr, const char *src_ptr); /ok!6.修饰符,作用域*不要在嵌套的代码块中出现相同的变量名!7.避免将函数的型参和函数的局部变量重名!1.未初始化的指针严重错误,注意!e.g: int *a; *a = 1;/我们并不知道指针变量a指向哪里!*越界指针和指向未知值的指针是常见错误的根源!3.把一个整形常量强制转换,来创建指针常量;e.g:int *ptr; ptr = (int *)1;4.if pointer point

5、to same array,pointer variable could use 加减,比较运算符,来判断它们在数组中的相对位置。5.注意不能向函数传递一个NULL指针,没有任何意义。 向函数传递指针就是为了解决函数只能return一个值的问题,而且还是单向的值传递。 用指针就可以让函数返回二个以上的值,实质就是在子函数的堆栈中对主调用函数中变量地址中的值回改。 c 专家编程char *pconst char *p1const char *p2char *p3typedef  char * char_ptr#define ptr char *宏类型名可以用其他类型说明符进行

6、扩展,typedef定义的不行:unsigned ptr   a;是合理的unsigned char_ptr b;则不对在连续几个变量的声明中typedef定义的类型能够保证声明中所有的变量具有相同的类型。而#define类型定义则无法保证。宏只是单纯的替换。 不要对结构使用typedef,struct关键字可以给阅读这个代码的人更多的提示。数组和指针并不相同!定义: 只能出现在一个地方。 确定对象的类型并分配内存,用于创建新对象。例如:int my_array100;声明: 可以多次出现      &#

7、160;       描述对象的类型,用于指代其他地方定义的对象。例如:extern int my_array;nm程序可以列出函数库所包含的函数。1、数据段保存在目标文件中2、bss段不保存在目标文件中,目标文件只保存bss段在运行时需要的大小。3、文本段最容易受优化的影响。程序数据段保存初始化的全局和静态变量(包括bss段,bss段只保存没有值的变量,例如int a20将保存在bss段,而int a20 = 1, 2, 3, .将保存在数据段)。堆栈用于保存局部变量、临时数据、传递到函数中的参数等。堆(heap)用于动态内存分配,

8、调用malloc函数将在堆上分配内存。(static 局部变量保存在数据库区)虚拟地址空间的最低部分未被映射,也就是说它位于进程的地址空间内,但并未赋予物理地址,所以对他的任何引用都是非法的。典型情况下,它是从地址0开始的几k字节。它用于捕捉使用空指针和小整型指针引用内存的情况。1、堆栈为函数内部声明的局部变量提供存储空间。按c语言的术语,这些变量被称为“自动变量”。堆中所有的东西都是匿名的不能按名字访问,只能通过指针间接引用。2、进行函数调用的时候,堆栈存储与此有关的一些维护性信息。(这些信息被称为堆栈结构(stack frame)或者过程活动记录(procedure activation

9、record)。包括函数调用地址、任何不适合装入寄存器的参数以及一些寄存器值的保存。3、堆栈也可被用作暂时存储区。(比如计算一个很长的算术表达式的时候用于保存中间结果)。通过alloca()分配的内存就位于堆栈中。如果想内存在函数调用后仍然有效就不能使用alloca()来分配内存(会被下一个函数调用覆盖)。绝大多数的处理器中堆栈是向下增长的,也就是朝着低地址的方向生长。检查源代码工具:cb c程序美化器,使源文件有标准的布局和缩进格式indent 与cb作用相同cdcel 分析c语言声明cflow 打印程序中调用者和被调用者的关系cscope 

10、一个基于ascii码的c程序的交互式浏览器ctags 创建一个标签文件,加快检查源程序的速度lint c程序检查器sccs 源代码版本控制系统vgrind 格式器,用于打印漂亮的c列表用于监察可执行文件的工具:dis 目标代码反汇编工具dump-Lv 打印动态链接信息ldd 打印文件所需的动态链接信息nm 打印目标文件的符号表strings 查看嵌入于二进制文件中的字符串sum 打印文件的检验和程序块计数帮助调试的工具:truss 打印可执行文件所进行的系统调用ps 显示进程

11、的特征ctrace 修改源文件,文件执行时按行打印debugger 交互式调试器file 显示一个文件包含的内容性能优化辅助工具:collector 在调试器控制下收集运行时性能数据(sunos 独有)analyzer 分析已收集的性能数据(sunos独有)gprof 显示调用图配置数据prof 显示每个程序所消耗时间的百分比tcov 显示每条语句执行次数的计数(确定一个函数中计算密集循环)time 显示程序所使用的实际时间和cpu时间字符常量的类型是int型的,因此:printf("%d &q

12、uot;, sizeof(''A''); 的结果是4(32位机)而不是1;但在c+中字符常量的类型是char型的。数组和指针可交换性总结:1、用ai这样的形式对数组进行访问,总是被编译器“改写”或解释为像*(a+i)这样的指针访问。2、指针始终是指针。它绝不可以改写成数组。你可以用下标形式访问指针,一般都是指针作为函数参数时,而且你知道实际传递给函数的是一个数组。3、在特定的上下文环境中,也就是它作为函数的参数(只有这种情况),一个数组的声明可以看作是一个指针。作为函数参数的数组(在一个函数调用中)始终会被编译器修改成指向数组第一个元素的指针。4、把一个数组定义

13、为函数参数的时候,可以选择把它定义为数组,也可以选择把它定义为指针。不管选择哪种方法,在函数内部事实上获得的都是一个指针。5、在其他所有情况中,定义和声明必须匹配。如果定义了一个数组,在其他文件对他进行声明时必须把它声明为数组,对于指针也一样。只有字符串常量才可以初始化指针数组,因此int *a =                  1, 2, 3,       &#

14、160;         1, 2,                  3, 4               /初始化失败在实践中不要把realloc函数的返回值直接赋给字符指针,如果realloc()失败,他会使该指针

15、的值变成NULL,这就无法对现有的表进行访问。c+类的通常形式class name          访问控制:声明                           .      

16、60;   访问控制:声明                           .                 ;访问控制是一个关键字,它说明谁可以访问接下

17、来声明的函数和数据。访问控制可以是:1、public:属于public的声明在类的外部可见,并可按需要进行设置、调用和操纵。一般的原则是不要把类的数据做成public的,因为让数据保持私有才符合面向对象编程的理论:只有类本身才能改变自己的数据,外部函数只能调用类的成员函数,这就保证了类的数据只会以合乎规则的方式改变。2、protected:属于protected的声明的内容只能由该类本身的函数以及从该类所派生的类的函数使用。3、private:属于private的声明内容只能被该类的成员函数使用。private声明在类外部是可见的(名字是已知的)但却是不能访问的。另外还有两个关键字也会影响访问

18、控制,friend和virtual。这两个关键字每次只能作用于一条声明。而且这两个关键字后面不跟冒号,属于friend的函数不属于类的成员函数,但可以像成员函数一样访问类的private和protected成员。friend可以是一个函数,也可以是一个类。virtual:告诉编译器该成员函数是多态的(也就是虚拟函数)类的成员函数可以在类中定义也可以在类外部定义例如class Fruit  public : void peel()printf("in peel ")  private: int weight;class Fruit  public

19、 : void peel();  private: int weight;void Fruit:peel()  printf("in peel ");构造函数:绝大多数类都至少具有一个构造函数,当类的一个对象被创建的时候,构造函数被隐式的调用,它负责对象的初始化。析构函数:是一个清理函数,当对象被销毁时,析构函数被自动调用。 c和指针  在程序中要屏蔽大段代码的时候使用#if 0  statements#endif可以有效的将代码从程序中屏蔽,而使用/* */注释时可能会因为代码内部含有注释而失败。字符串常量在表达式中使用时

20、是使用它的地址,因此不能用字符串常量给数组进行赋值。int *a, b, c;int* a, b, c;a是整形指针typedef char * ptrtocharptrtochar a, b;  a, b都是字符指针#define ptrtochar char *ptrtochar a, b;a是字符指针,b是字符宏类型名可以用其他类型说明符进行扩展,typedef定义的不行:unsigned ptr   a;是合理的unsigned char_ptr b;则不对标志符链接属性:extern和static用于在声明中修改标志符的链接属性static只对缺省链接属

21、性为external的声明才有改变链接属性的效果存储类型:auto  static  register变量的缺省存储类型取决于它的声明位置。凡是在任何代码块之外声明的变量总是存储于静态内存中的,即不属于堆栈的内存,这类变量称为静态变量。对于这类变量,你无法为它指定其他的存储类型。在代码块内部声明的变量的缺省类型是自动的。存储于堆栈中,称为自动变量。在程序执行到声明自动变量的代码块时,变量才被创建。当程序执行流离开该代码块时,自动变量将被销毁。如果代码块被多次执行,则自动变量也将创建多次。对于自动变量,在声明时加上static关键字,可以使它的存储类型从自动变为静态。它将在整

22、个程序执行期间一直存在。修改变量的存储类型并不表示修改该变量的作用域。函数行参不能声明为静态变量,因为实参总是在堆栈中传递给函数。(用于支持递归)不显示指定初始值,静态变量将初始化为0。函数的局部变量在函数每次调用时,可能占据不同的位置。因此自动变量没有缺省的初始值。显示的初始化将在代码块的起始处插入一条隐含的赋值语句。这种初始化的4个后果:1、自动变量的初始化同赋值语句相比效率并没有变化(除了声明为const的变量之外),在声明变量的同时进行初始化和先声明后赋值只有风格之差,并无效率之别。2、每次执行这个代码块都将重新进行初始化。3、由于初始化是在运行时执行,可以使用任何表达式作为初始值4、

23、除非对自动变量进行显示的初始化,否则自动变量创建时,它们的值总是垃圾static关键字:当用于不同的上下文环境的时候static具有不同的含义。用于函数定义或者代码块之外的变量声明时,static关键字用于修改标志符的链接属性,从external改为internal。标志符的存储类型和作用域不受影响,这种方式声明的函数和变量只能在声明它的源文件中访问。当用于代码块内部的变量声明的时候,static关键字用于修改变量的存储类型,从自动变量修改为静态变量,但变量的链接属性和作用域不变。这种方式声明的变量在程序执行之前被创建,并在整个程序执行期内一直存在。作用域、链接属性和存储类型总结 变

24、量类型 |  声明的位置  | 是否存于堆栈 |     作用域    | 声明为static.  全局    |所有代码块之外|      否      |声明处到文件尾 | 不允许从其他源文件访问  局部    |代码块起始处  |      是 

25、0;    | 整个代码块    | 变量不存在堆栈中,值在程序整个执行期一直保持 形式参数 | 函数头部     |      是      | 整个函数      | 不允许+和-操作符都复制一份变量值的拷贝作为表达式的值。因此+a = 10是错误的,因为+a并不是一个左值。/* When the system is little e

26、ndian, it returns 1; otherwise 0.*/int is_little_endian()  int one = 1;  return *(char*)&one;间接访问操作符(*)只能用于指针变量标准允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较单不允许与指向数组第一个元素之前的那个内存位置的指针进行比较所以for (vp = &valueslen - 1; vp >= &values0; vp-)  *vp = 0;存在一个问题:当数组的第一个元素被置零后,vp的值还将减1。接

27、下去比较vp和&values0的结果是不确定的。因为vp到了数组边界之外。int *func(void);void提示没有任何参数, 而不是表示它有一个类型为void的参数抽象数据类型(abstract data type) ADT可以限制函数和数据定义的作用域这个技巧也被称为黑盒设计指针使用效率:1、当根据某个固定数目的增量在一个数组中移动的时候,使用指针变量将比使用下标产生效率更高的代码。当这个增量是1且机器具有地址自动增量模型时,这点表现更为突出。2、声明为寄存器变量的指针通常比位于静态内存和堆栈中的指针变量效率更高(具体取决与所使用的机器)3、如果可以通过测试一些已经初始化并经

28、过调整的的内容来判断循环是否结束,那么就不要用一个单独的计数器。4、那些必须在运行时求值的表达式较之&arraySIZE、array+SIZE这样的常量表达式往往代价更高。char m="hello"char *m="hello"第一种情况下"hello"是一个初始化列表,而第二种情况下"hello"是一个字符串常量。作为函数参数的多维数组多维数组每个元素本身就是一个数组,编译器需要知道它的维数,以便为函数行参的下标表达式进行求值。因此func(int (*a)10);才可以接收int s210作为参数。而写成func(int *a);是不对的。一个文件中同时出现两个struct的声明struct   int a;  char b;  float c; *a;struct   int a;  char b; 

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论