当前位置: 首页 > C, C/C++ > 正文

《C专家编程》学习笔记1

1.整形升级和寻常算术转换:

char,short int 或者位段,包括他们的有符号和无符号型,以及枚举类型,可以使用在需要的int 或unsignede int 的表达式中。如果int可以完整的表示源类型的所有值,那么该源类型的值就转换为int  型,否则转换为无符号类型,这称之为整形升级。

      对于其他类型的转换,如果有两个操作数:转换关系如下:

      long double   ——   others  type      —————>    long  double

      double          ——-   others type       ————–>     double 

      float              ——    others type          ————–>    float

      否则进行整形升级,

      unsigned  long int    ——— others type  ———–>    unsigned long int

      long  int    ———————–   unsigned int    如果长整形能够完整的表示无符号整形的所有值,那么无符号整形被转换为长整型,否则全部转换为无符号长整形。

       

建议:在使用位段和二进制掩码的时候才使用无符号数,其他情况下建议不要使用这类无符号的类型。


NULL表示什么也不指向(空指针),NUL表示用于结束一个ASCII字符串。


switch语句的一些问题;

default 可以自由出现在任意的位置,如果没有它且没有与之匹配的case那么,这个switch语句不做任何事,C语言不检查这种情况,PASCAL语言却是检查的。

每个case和default的顺序可以是任意的,习惯上把default放在最后。

在每个case后没有break的情况称之为“fall through”这种情况下需要特殊注释出来。


理解C语言的优先级规则:

A.声明从它的名字开始读取,然后按照优先级顺序依次读取。

B.优先级从高到底依次是:

          1.声明中被括号括起来的那部分。

          2.后缀操作符:

  括号()表示这是一个数组,而方括号【】表示这是一个数组。

          3.前缀操作符:*星号表示“指向。。。。。。的指针”。

       C。如果const 或 volatile 关键字的后边紧跟类型说明符,那么它作用于类型说明符。在其他的情况下,作用于它左边紧邻的指针星号。

注意typedef 和define 的区别

        typedef  不可以组合定义,define只作用于第一个参数。


声明与定义的区别:

定义:只出现在一个地方,确定对象的类型并分配内存,用于创建新的对象,例如int a[100];  相当于特殊的声明并且为对象分配内存。

声明:可以多次出现,描述对象的类型,用于指代其他地方定义的对象(extern  int   a  ; )说明的并非自身,而是描述其他地方的对象。

左值与右值的区别:

              x  =  y ;

      x是左值本质表示一个地址,右值Y在这里本质表示一个内容。

数组引用与指针引用的区别:

          char  a[9] = “abcdefgh”  ;

          c = a[i]      ;

       首先编译器会取a的地址就是,数组元素的首地址,然后取i的值与首地址相加

然后取出地址内的内容。


char * p  ;

        c  =   *p  ;

        首先编译器符号表有一个符号P,假设它的地址为5000,

然后编译器会取出地址5000的内容就是数组的首地址,然后取出地址内的内容。

当定义为指针,但以数组方式引用时,这时候的取值方法是上边两个方式的混合。

现在总结如下:

1.取得符号表中p的地址,提取存储于此处的指针。

2.把下标所表示的偏移量与指针的值相加,产生一个地址。

3.访问上面这个地址取得字符。

定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义的同时赋给指针一个字符串常量进行初始化。其中字符串常量被存放在只允许读的文本段中,防止被修改。

再探数组与指针:

    我们先从声明开始:

     声明本身还可以进一步分成3种情况:

1.外部数组的声明。

2.数组的定义。

3.函数参数的声明。

所有作为函数参数的数组名总是可以通过编译器转换为指针。

(小心在一个文件中定义为数组,在另一个文件中声明为指针这种情况)

所以:数组的声明就是数组,指针的声明就是指针,对于编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址。

在表达式中,指针和数组是可以互换的,因为他们的最终形式都是指针。

但是为什么C语言把数组形参当作指针,这只是出于效率的考虑。


没有办法把数组本身传递给一个函数,因为它总是被自动转换为指向数组的指针,由此sizeof运算符不再可以帮助我们求数组的长度,这种求法只可以在本地栈中使用。


现在:

数组和指针可交换性总结:

1.想a[1]总是被编译器改写为*(a+1)这种情况。

  2.指针始终是指针它决不可以改写成数组,但是可以用下标访问的方式,访问内容,也可以作为参数传递。

3.在特定的上下文中,也就是它作为函数的参数(有且只有这一种情况)一个数组的声明可以看做是一个指针。作为函数参数的数组始终会被编译器修改成为指向数组第一个元素的指针。

4.因此,把一个数组定义为一个函数参数的时候你可以任意选择是定义成指针还是定义为数组,毕竟编译器得到的只是一个指针。

5.在其他的情况中,声明和定义必须匹配。

向函数传递一个数组的方法:

    1.增加一个额外的参数,表示元素的数目。

    2.在数组的最后添加一个特殊值,提示它是数组的结尾,因为C语言不检查结尾。

关于指针和数组的最后一个问题:

如和交换两个值:

 其实这几个交换方式各有优缺点:

第一种方法:明显要使用一个中间变量,

第二种方法:必须满足条件1.a与b都是原子操作且不会发生硬件失败,空间不够或数学运算失败。

第三种方法:有越界的可能性。


内存中的 “猫腻” :

C语言:先编译后连接。

B语言:先连接后编译。

段:

UNIX中,段表示一个二进制文件相关的内容块。

在inter X86中,段表示一种设计结果。是一些大小为64K的区域。

一般C程序有三个基本的段:BSS段,文本段,数据段。具体参见之前的一篇博文‘C与内存’。

堆栈段:

包含一种单一的数据结构,就是栈。

其中包含一个全局的指针SP用来提示栈的顶端。

作用:

1.堆栈为函数内部声明的局部变量提供存储空间。

2.进行函数调用时,堆栈存储与此有关的一些维护性信息,另外一个更常用的名字是过程活动记录。

3.堆栈也可以被用作暂时存储区。

堆栈是向下增长的,

过程活动记录:

简而言之,这个东西是C语言自带的用来监控被调用函数的。

包含:

局部变量,参数,静态链接,指向先前结构体的指针,返回地址。

在内存中这也是向下增长的。也就是朝着低地址方向生长。

版权声明:本文为博主原创文章,未经博主允许不得转载。

]]>

本文固定链接: http://zmrlinux.com/2015/05/05/%e3%80%8ac%e4%b8%93%e5%ae%b6%e7%bc%96%e7%a8%8b%e3%80%8b%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b01/ | Kernel & Me

该日志由 root 于2015年05月05日发表在 C, C/C++ 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 《C专家编程》学习笔记1 | Kernel & Me