数组和指针

数组和指针

数组和指针的统一性C语言的长处之一,用指针可以很方便地访问数组和模拟动态分配的数组。

多数的数组引用都会退化为数组第一个元素的指针,这是C语言中数组和指针等价的基础。因此,数组在C语言中是个二等公民:你永远也不能作为一个整体操作数组(例如:复制或将它们传入数组),因为一旦你提到数组的名字,你所得到的就是一个指针而不是一个数组了。

       关于char a[]=”hello”char *p=”world”的区别:

clip_image002[4]

       其中a为数组预留了6个字符的位置,而p只是提供了一个指针。本质区别为:一旦出现类似a的数组和类似p的指针,以后的操作就会按照不同的方法计算。

       数组和指针的区别

数组是一个由(同一类型的)连续元素组成的预先分配的内存块;

指针是一个对任何位置的(特定类型的)数据元素的引用;

数组自动分配空间,但是不能重分配或改变大小;

指针必须被赋值以指向分配的空间(可能使用malloc),但是可以随意重新赋值(即指向不同的对象),同时除了表示一个内存块的基址之外,还有许多用途;

数组和指针的联系

指针可以模拟数组;

几乎没有所谓数组的东西,下标操作符实际上是个指针操作符;

从更高的层次上看,指向一块内存的指针本质上也就是一个数组;

 

如果a是数组int a[10],那么对a的引用就是“int型的指针,而&a“10int的数组的指针

 

       sizeof操作符如果能够判断出数组的大小,就会返回数组的大小,如果数组的大小未知或者数组已经退化为指针,就不能提供数组的大小了。

 

空指针

空指针

l  所谓的空指针就是表示未分配或者尚未指向任何地方特殊指针;

l  在源码中用来表示空指针的空指针常量使用整数0,且在很多机器上都在内部采用所有位都是0的字来表示空指针,但C语言不保证第二点;

l  空指针在概念上不同于未初始化的指针。空指针可以确保不指向任何对象或函数,而未初始化的指针则可能指向任何地方

l  根据语言定义,在指针上下文中的值为0的整型常量表达式会在编译时转换为空指针,但是,传入函数的参数不一定被当做指针上下文。所以,在函数调用时对所有的空指针进行类型转换可能是防止可变参数和无原型函数出问题的最安全的方法;

l  为了让程序中的空指针使用更加明确,特意定义了一个标准预处理宏NULL,其值为空指针常量;

l  在有些编译器头文件中定义NULL0L,是因为在有些机器上指针比整型大,比如large模式的PC兼容机上;

l  关于空指针,有两条规则必须遵循:

n  当在源码中需要空指针常量时,用“0”“NULL”

如果在函数调用中“0”“NULL”用作参数,把它转换成被调函数需要的指针类型即可;

指针

指针

l  指针毫无疑问是C语言中最强大和最流行的功能之一;

l  指针的好处:

n  动态分配数组;

n  对多个相似变量的一般访问;

n  按引用传递函数参数;

n  各种动态分配的数据结构,尤其是数和链表;

n  遍历数组:例如解析字符串;

n  高效地、按引用复制数组和结构,特别是作为函数参数的时候;

l  不能对void*指针进行算术操作的原因是编译器不知道所指对象的大小;

没有什么通用指针类型void *指针只能保存对象(也就是数据)指针。但是,可以确保的是,所有的函数指针类型都可以相互转换,只要在调用之前转回了正确的类型即可。

表达式

表达式

l  函数调用时的参数的求值顺序是不确定的;

l  序列点:一个时间点,此刻尘埃落定,所有的副作用都已经确保结束;

l  在上一个和下一个序列点之间,一个对象所保存的值至多只能被表达式的求值修改一次,而且只有在确定将要保存的值的时候才能访问前一个值;

l  一旦一个表达式或程序未定义,则它的所有方面都会变成未定义;

l  三元操作符?:可以生成一个值,但是不能被复制;

结构、联合和枚举

结构、联合和枚举

l  所谓的抽象数据类型,应该只在源文件中看到细节才完美;

l  对于大工程而言,最好将函数原型和结构声明放在单独的头文件中;

l  在结构中,比较安全的定义方式是使用指针而不是数组;

l  不能使用==!=来比较结构是因为可能会遇到结构中没有使用的洞hole的随机内容而导致失败;

l  当结构作为函数参数传递的时候,通常会把整个结构都推进栈,需要多少空间就使用多少空间,正是为了避免这个代价,程序员经常使用指针而不是结构

l  为了广泛的可移植性,在读写文件的时候,最好使用二进制b选项;

l  正确地对齐是种编译器高效访问的策略;

l  将结构中的域按照从大到小的顺序排列可以最大限度地降低填充的影响;

l  结构为一级对象,而结构为二级对象,不能直接对结构进行赋值等;

l  在原来的ANSI C中,只有联合中的第一个成员可以被初始化,C99引入了指定初始式,可以用来初始化任意成员

l  联合无法跟踪到底是哪一个域在使用;

l  枚举的优点为:自动赋值;调试器在检验枚举变量时,可以显示符号值;它们服从数据块作用域规则。一个缺点是程序员不能控制这些非致命的警告,有些程序员则反感于无法控制枚举变量的大小;

l  位域冒号:指定二进制大小的方法只适用于结构和联合的成员;

位域是可以移植的;