C专家编程

1.break语句跳出的是最近的那层循环语句或switch语句。

2.相邻字符串会合并“abc”“def”=“abcdef”

3.函数声明要么static要么extern,extern时注意interpositioning问题,用户编写和库函数同名的函数并取而代之的行为

4.返回类型为函数的指针的函数   int(* fun())()

5.返回类型为数组的指针的函数  的数组  int(* fun())[]

6函数指针数组  int (* fun[])()

7.函数的参数在传递是尽可能存放在寄存器中,而非一味地从右向左压栈

8.可以利用结构体实现整个数组的赋值

9.char * const *(*next)()  指向返回指向char型常量的指针的指针的函数的指针

10.通过typedef可以简化以上数据类型

11.typedef与#define

    1.可以用其它类型说明符非宏类型名进行扩展,但对typedef所定义的类型名却不能

    #define peach int

    unsigned peach i;//good

    typedef int banana;

     unsigned banana i;//bad

     2.typedef所定义的类型能保证声明中的都为同一类型

    #define int_ptr int *

    int_ptr chalk, cheese;

    typedef int * char_ptr;

    char_ptr chalk, cheese;

12.不要为了方便起见对结构使用typedef,应用在:1.数组、结构、指针及函数的组合类型2.可移植类型 short,long, int的修改3.方便后面做强制类型转换

13.声明:描述其它地方创建的对象

     定义:为对象分配内存

14.数组与指针:对于编译器数组是地址,指针是地址的地址

      1.数组名不可赋值

      2.在编译器中数组名是一个内存地址不要增加指令首先取得具体的地址,而指针p是存放的地址的地址

      3.指针存放的是数据的地址,数组存放的是数据

      4.指针一般用于动态数据结构,数组用于固定数目同类型元素

      5.指针指向匿名数据,数组自身为数据名

      6.指针用字符串常量初始化,则字符串常量为只读的,若为数组则可修改

15.静态链接:函数库的一份拷贝是可执行文件的物理组成部分   .a

     动态链接:可执行文件只包含了文件名,让载入器在运行时能够寻找程序所需的函数库。可执行文件体积小,运行速度慢,磁盘空间利用率高,链接-编辑阶段时间短   .so

     静态共享库:介于两者之间

16.头文件的名字通常不与它所对应的函数库名相似

17.interpositioning,不要让任何符号成为全局的,除非有意把他们作为程序的接口之一。使用-m选项可检查

18.Unix 段:二进制文件相关的内容块

     X86段,地址空间并非整体,而是分成一些64K大小的区域

     代码段 可执行代码、字符串常量

     数据段 已初始化全局变量、已初始化全局静态变量、局部静态变量、常量数据

     BSS段 未初始化全局变量,未初始化全局静态变量

     局部变量、函数参数

     动态内存分配

19.如果想返回一个指向函数内部定义的变量的指针,要把哪个变量声明为static。

20.函数被调用,有一个过程活动记录,活动记录一般要包含一个指向它的外阐述的活动记录的指针,即静态链接(与之前的不同)。过程活动可能并不在堆栈中,寄存器中更快

21.如何在进程中支持不同的控制线程:为每个控制线程分配不同的堆栈(大小为1Mb)

22.setjmp(jmp_buf j),必须首先被调用,“使用变量j记录现在的位置,函数返回0”.

     longjump(jump_buf j, int i),“回到j所记录的位置,函数返回i”,goto不能跳出C语言当前的函数,longjump可以,但只能跳到曾经到过的地方

23.volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。

volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。

其中编译器编译优化是:
由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。

24.用grep调试操作系统内核

25.内存地址的形成:1.取得16位寄存器的值,并左移4位;2.加上16位偏移地址

26.虚拟内存:用廉价但缓慢的磁盘来快速扩充快速但昂贵的内存。程序需要使用虚拟内存区段的内容会被载入物理内存,物理内存中的数据一段时间不用就被转移到硬盘

27.realloc

    extern void *realloc(void *mem_address, unsigned int newsize);    不要把realloc的返回值直接赋给字符指针,若realloc失败,会返回NULL,导致无法对现有表的访问

    指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
    新的大小一定要大于原来的大小,不然的话会导致数据丢失!
28.内存损坏:释放或改写还在使用中的内存
29.内存泄漏:未释放不再使用的内存。症状:罪魁进程速度减慢,原因是体积大的进程更有可能被系统换出。检查swap -s      或  netstat,vmstat
30.进程换出:进程不马上运行,操作系统暂时取回所有分配给他的物理内存资源,将改进程的所有相关信息都备份到磁盘上
31.总线错误:一般由未对齐的读或写引起
32.段错误:访问的内存超出了系统所给这个程序的内存空间
33.状态机:1.SWITCH 2.状态函数需要多个参数时,使用int argc和 * argv[]
34.增量开发与显示代码调试
      显示代码调试:sendmail与make,修改程序直到程序能够运行
35.为何进行强制类型转换:消除歧义
36.数组和指针  是一样的  情形
    1.表达式中的数组名(非声明)被编译器当作一个指向数组第一个元素的指针
    2.下标总是与指针偏移量相同
    3.作为函数定义的形式参数  
37.数组取下标操作符与操作数是可以交换的  a[6]=1; 等价于6[a]=1;
38.声明一个字符串指正数组,并更具需要为这些字符串分配内存,会打打节省系统资源(锯齿状数组)
39.数组的数组被改写为数组的指针
40.C语言中,无法向函数传递一个普通的多维数组,必须提供除了最左边一维以外所有维的长度,调用时必须与形参匹配
41.C语言中const int 不能被当作一个整型常量表达式,故不能在数组的[]中,C++中可以
42.C++提倡特性:
    1.类
    2.构造函数,析构函数,仅限函数体简单的例子
    3.重载
    4.单冲继承与多态
  多态性 
  指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
  a、编译时多态性:通过重载函数实现    一个类有多个同名函数
  b、运行时多态性:通过虚函数实现。    继承和虚函数    父类指针更具赋值操作时右值的类类型,确定指向父类或子类
       无虚函数的覆盖,则根据左值指针类型调用函数   无多态
    不提倡:
    1.模板
    2.异常
    3.虚基类
    4.多重继承
43.C与C++  
    1.C++中typedef定义名字不能与已有结构标签冲突,C语言可以,因为他们分属不同的名字空间
     2. void* 指针赋值给别的类型指针时, C++要类型转换,C不需要
    3.C++ 声明语句可以在任何地方
    4.C++一个内层作用域的结构名会隐藏外层空间中相同的对象名,C语言不会
44.纯虚函数:函数本事没有代码,用于声明
纯虚函数的类在其派生类中必须定义自己这个函数的版本,而且纯虚函数是没有实际意义的,他的目的告知编译器派生类将会定义自己的版本。
45.虚基类: 至少包含一个纯虚函数,用于派生         
46.虚函数:是可实现方法,表示派生类可以覆盖呢该方法
虚函数仅表示派生类可以定义自己的版本,但是基类也可以有意义,若没有定义自己的版本,将使用基类的版本。
原文地址:https://www.cnblogs.com/chengxuyuandashu/p/3594273.html