关于数组和指针
指针类型总结
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
1.数组 != 指针
char a[ ] 和 char *a
数组定义 char a[6] 请求预留 6 个字符的位置, 并用名称 “a” 表示。 也就
是说, 有一个称为 “a” 的位置, 可以放入 6 个字符。
而指针申明 char *p, 请求一个
位置放置一个指针, 用名称 “p” 表示。 这个指针几乎可以指向任何位置: 任何字符
和任何连续的字符, 或者哪里也不指
例如声明
char a[] = "hello";
char *p = "world";
将会初始化下图所示的数据结果(内存区域示例图):
+---+---+---+---+---+---+
a: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+
+-----+ +---+---+---+---+---+---+
p: | *======> | w | o | r | l | d |\0 | (指向一片内存区域)
根据 x 是数组还是指针, 类似 x[3] 这样的引用会生成不同的代码。
从 a 的位置开始跳过 3 个, 然后取出那个字符. 如果它看到 p[3], 它生成代码找到
“p” 的位置, 取出其中的指针值, 在指针上加 3 然后取出指向的字符。 换言之, a[3]是名为 a 的对象 (的起始位置) 之后 3 个位置的值, 而 p[3] 是 p 指向的对象的 3 个位置之后的值.
本质的区别在于类似 a 的数组和类似 p 的指针一旦在表达式中出现就会按照不同的方式计算!
2.指针和数组等价的条件
(1)数组和指针的算法定义可以用指针方便的访问数组或者模拟数组
;从此层面上,数组和指针是等价可以共用的
说数组和指针 “等价”不表示它们相同, 甚至也不能互换。
一个 T 的数组类型的左值如果出现在表达式中会蜕变为一个指向数
组第一个成员的指针(除了三种例外情况); 结果指针的类型是 T 的指针。
这就是说, 一旦数组出现在表达式中, 编译器会隐式地生成一个指向数组第一
个成员地指针, 就像程序员写出了 &a[0] 一样。 例外的情况是, 数组为 sizeof 或 &
操作符的操作数, 或者为字符数组的字符串初始值。
作为这个这个定义的后果, 编译器并那么不严格区分数组下标操作符和指
针。 在形如 a[i] 的表达式中, 根据上边的规则, 数组蜕化为指针然后按照指针变量的方式如 p[i] 那样寻址,
尽管最终的内存访问并不一样。 如果你把数组地址赋给指针:
p = a; 那么 p[3] 和 a[3] 将会访问同样的成员。
3.作为函数形参的数组和指针声明可以互换
由于数组会马上蜕变为指针, 数组事实上从来没有传入过函数。 允许指针参
数声明为数组只不过是为让它看起来好像传入了数组, 因为该参数可能在函数内
当作数组使用。 特别地, 任何声明 “看起来象” 数组的参数, 例如
void f(char a[])
{ ... }
在编译器里都被当作指针来处理, 因为在传入数组的时候,那正是函数接收到
的.
void f(char *a)
{ ... }
这种转换仅限于函数形参的声明, 别的地方并不适用
4.多维数组
(1)二维数组名为指向指针的指针
首先,通过优先级判断来确定它属性.
int (*a)[1]; // ()的优先级大于[], 因此p先于*结合, (*p)是一个指针
int *a[1]; // *的优先级小于[], 因此p先于[]结合, p[4]是一个数组
int *(a); // ()两个优先级相同, 因此从左到右按顺序执行,(*p)是一个指针
int *a(); // ()优先级高于*, 因此p先于()结合, p()是一个函数
然后,考虑:如果是指针,则考虑指针指向的内容
如果是数组,则考虑数组的数据类型和长度
如果是函数,则考虑函数的参数列表和返回值
int (*a)[1]; // 指向数组的指针(数组指针)
int *a[1]; // 指向指针的数组(指针数组)
int *(a); // 指向函数的指针(函数指针)
int *a(); // 指向指针的函数 (指针函数)
5.指针数组和数组指针
(1)指针数组:它实际上是一个数组,数组的每个元素存放的是一个指针类型的元素。
int* arr[8];
//优先级问题:[]的优先级比*高
//说明arr是一个数组,而int*是数组里面的内容
//这句话的意思就是:arr是一个含有8和int*的数组
(2)数组指针:它实际上是一个指针,该指针指向一个数组。
int (*arr)[8];
//由于[]的优先级比*高,因此在写数组指针的时候必须将*arr用括号括起来
//arr先和*结合,说明p是一个指针变量
//这句话的意思就是:指针arr指向一个大小为8个整型的数组。