以下是从内存寻址的角度描述一些更多的差异:
I. char **p;
p
是类型为 char
的双指针
声明:
char a = 'g';
char *b = &a;
char **p = &b;
p b a
+
| | | | | |
|0x2000|
| | | | | |
+
0x3000 0x2000 0x1000
Figure 1: Typical memory layout assumption
在上述声明中,
a
是包含字符
g
的
char
类型。指针
b
包含现有字符变量
a
的地址。现在
b
是地址
0x1000
,
*b
是字符
g
。最后将
b
的地址分配给
p
,因此
a
是字符变量,
b
是指针,而
p
是指向指针的指针。这意味着
a
包含值,
b
包含地址,如下图所示,
p
包含地址的地址。
在各自的系统上,sizeof(p) = sizeof(char *)
;
II. char *p[M];
p
是字符串数组
声明:
char *p[] = {"Monday", "Tuesday", "Wednesday"}
p
+
| p[0] | +
0 | 0x100|
| | +
|
| p[1] | +
1 | 0x200|
| | +
|
| p[2] | +
2 | 0x300|
| | +
+
Figure 2: Typical memory layout assumption
在这个声明中,
p
是一个包含3个指向
char
类型的指针的数组。意味着数组
p
可以包含3个字符串。每个字符串
(Monday, Tuesday & Wednesday)
存储在内存中的某个位置
(0x100, 0x200 & 0x300)
,它们的地址分别存储在数组
p
中的
(p[0], p[1] & p[2])
中。因此,它是一个指针数组。
注: char *p[3];
1. p[0], p[1] & p[2] are addresses of strings of type `char *`.
2. p, p+1 & p+2 are address of address with type being `char **`.
3. Accessing elements is through, p[i][j] is char; p[i] is char *; & p is char **
这里 sizeof(p) = 字符���组数量 * 指针所占字节大小
III. char p[M][N];
p
是一个固定长度字符串的数组,维度为 M x N
声明:
char p[][10] = {Monday, Tuesday, Wednesday}
p 0x1 2 3 4 5 6 7 8 9 10
+
0 | M o n d a y \0 \0 \0 \0|
1 | T u e s d a y \0 \0 \0|
2 | W e d n e s d a y \0|
+
Figure 3: Typical memory layout assumption
在这个例子中,数组
p
包含3个字符串,每个字符串都包含10个字符。从内存布局可以看出,
p
是一个大小为
MxN
的字符二维数组,在我们的例子中是
3x10
。这对于表示相等长度的字符串非常有用,因为当字符串比声明
char *p[]
少于10个字符时,可能会浪费内存,而
char *p[]
没有浪费内存,因为字符串长度未指定,它对于表示不等长度的字符串非常有用。
访问元素与上述情况类似,
p[M]
是第M个字符串,
p[M][N]
是第M个字符串的第N个字符。在这里
sizeof(p) = (M行 * N列) * sizeof(char)
是二维数组的大小。
char (*p)[]
,它是指向字符数组的指针。 - aragaer