一维数组:
先看两个最简单的语句 int a ; int b[10]; 显然a是一个整形变量(标量),b[10]称为数组,表示一些整形值得集合,b表示一个指向整形的指针常量,表示数组元素的首地址,再此不能根据这个事实得出数组和指针是相同的应该注意数组。
数组名并不用指针来表示的两种场合:数组名作为sizeof操作符或单目操作符&的操作数
下面介绍一下数组的赋值,考虑下面几个例子 int a[10]; int b[10]; int c=&a[0];
先看一下最后一条语句c=&a[0]是一个指向数组第一个元素的指针,相当于c=a;这条语句解释了数组名的真正含义,说明数组名是一个指针的拷贝,c所指向的是数组的第一个元素;再看两个非法操作有助于更深刻的理解数字组的赋值操作b=a;这个表达式是非法的因为你不能使用赋值符把数组的所有元素复制到另一个数组中,而必须使用循环一个一个的复制;a=c;表达式中a是一个常量,不能被修改,所以不能把它理解为某种指针赋值,把c的值复制到a中;
接下来我们将看一下最让人容易搞混的下标引用操作:
int b[10] *(b+4) 指向数组第一个元素向后移四个整数位置的长度
再此我们应该知道这个概念:除了优先级之外,下标引用和间接访问完全相同
例如表达式array[3]和表达式*(array+3)表达式是相同的;同时也可以在使用下标引用的地方,使用对等的指针表达式来代替,如下面的两个语句是相等的:int array[10];和
int *pa=array+2; 同时指针加法运算时会对2进行调整,产生的指针ap指向array[2],如下图所示:
下面分析各个涉及到ap的表达式和其对应的array对等的表达式
ap 等价array+2或者&array[2] ap所指向的内存的值
*ap 等价array[2]或者*(array+2)或者ap[0] 指向ap所指向的位置
ap+6 等价array+8或者&array[8] 指向array[2]向后移动6个整数位置的元素
*ap+6 等价array[2]+6 先执行*在执行+,所以应该是ap指向元素在与6相加
*(ap+6) 等价array[8] 括号使的先强制进行加法在进行解引用操作&ap 无等价array表达式 因为此时无法预测编译器会把ap放在array的什么位置ap[-1] 等价array[1] 将ap指向的元素向左偏移一个单位得到他前一个元素
ap[9] 等价array[11] 数组越界,很多机器上指向最后一个元素后面的第 二个位置,但是并没有办法预测这个值是什么
在介绍一个比较有趣的访问:2[array]=*(2+array)=*(array+2)=array[2]这个表示式子的转化关系并不是指从左向右赋值
指针与下标运算的关系说明:
1、下标更容易理解,在可读性方面有一定优势;
2、下标绝不会比指针更有效率,但指针有时候会比下标更有效率。
3、再编程的过程中,应当注意不要为了效率上的细微差别而牺牲可读性。
关于指针效率的几点说明:
1、当以某个固定数目增量在数组中移动时,使用指针变量更有效率。
2、声明为寄存器变量的指针通常比位于静态内存和堆栈中的指针效率更高。
3、通过测试一些已初始化并经过调整的内容来判断循环是否应该终止,可以避免使用计数器。
数组和指针的区别:
int a[5]; int *b; 声明数组时编译器会根据指定元素的数量为数组内存保留内存空间,然后再创建数组名,指向数组的首元素;声明为指针变量时,编译器只为指针变量保留内存空间,并不为任何整形值分配内存空间。因此上面的两个表达式中,*a是完全合法的,*b却是非法的,*b访问的内存中不确定的某个位置,或者直接导致程序结束,但是b++可以通过编译,a++却不行,因为a的值是常量。
数组的小知识点:
1、声明数组参数时,调用函数传递的是一个指针。
2、数组初始化时,可以使用花括号或者双引号,再此存储于静态内存的数组只能初始化一次,未初始化时数组元素会被自动设置为0,对于自动变量如果为初始化,其中存的便是任意值,因为每次所处的内存位置可能并不相同。
3、数组可以省略最后几个初始值,且可以省去第一个长度值。
多维数组:
存储顺序:按照最右边的下标率先变化的原则
数组名:依然是一个指针常量,指向数组的第一个元素,唯一的区别是多维数组第一维元 素实际上是另一个数组。
下标引用:先看这个二维数组int arr[3][10],他的各种下标引用如下图所示:
初始化:(1)只给出一个长长的初始值列表;
(2)用多个花括号将初始值列表进行逐行定界
指针数组:字符串的列表可以以矩阵的形式存储,也可以指向字符串常量的指针数组形式存储。在矩 阵中,每行必须与最长字符串的长度一样长,但他不需要任何指针;指针数组本身要占用空间,但每个指针所指向的字符串所占用的内存空间就是字符串本身的长度。