假设
char *p;
char a[] = "Hello";
p = a;
此处 p 的地址为 a ,其指向字符串 Hello
的第一个元素换句话说,我们需要一个间接操作符来访问字符串 Hello
的第一个元素当我们有字符串数组时,为什么我们需要两个 Indirection 运算符,而array只是一堆具有相同数据类型的内存位置
答案 0 :(得分:5)
正如我认为的意思,对于任何数组或指针'a'和索引i
,表达式a[i]
等于*(a + i)
。
这意味着a[0]
等于*(a + 0)
。 *(a + 0)
等于*(a)
,等于*a
。
如果a
是一个字符数组,如您的示例所示,则*a
实际上是第一个元素的值。但是如果a
是一个数组数组,例如
char a[2][4] = { "Foo", "Bar" };
然后*a
是a
的第一个元素 still ,在这种情况下,它是另一个数组(其中包含字符串{ {1}})。并且使用与上述相同的逻辑,由于"Foo"
是另一个数组,因此*a
是该嵌套数组的第一个元素,在我的示例中是字母**a
。
这就是为什么您需要“两次间接访问”才能到达第一个数组的第一个字母。
哦,往后看,'F'
(与我的数组数组)等于**a
。
如果我们采用数组数组
a[0][0]
并显示如何将其布置在内存中,就像这样(添加了指针):
+-----+-----+-----+-----+-----+-----+-----+-----+ | 'F' | 'o' | 'o' | 0 | 'B' | 'a' | 'r' | 0 | +-----+-----+-----+-----+-----+-----+-----+-----+ ^ ^ | | &a[0][0] &a[1][0] | | &a[0] &a[1] | &a
如果我们使用指针char a[2][4] = { "Foo", "Bar" };
,&a
和&a[0]
,它们都指向相同的位置。 但是 它们不是同一类型!
&a[0][0]
是指向整个数组&a
的指针,其类型为a
char (*)[2][4]
是第一个子数组的指针,其类型为&a[0]
char (*)[4]
是指向第一个数组中第一个字符的指针,其类型为&a[0][0]
进行“取消引用”对于不同的指针意味着不同的事情。
答案 1 :(得分:2)
请考虑以下字符串数组:
char* greeting[] = {"Hello", "World"};
上面的代码可能(在一个简单的体系结构上)导致这样的内存布局:
1000 'H' 'e' 'l' 'l'
1004 'o' 00 'W' 'o'
1008 'r' 'l' 'd' 00
100c 10 00 10 06
字符串数组greeting
位于内存地址100c,由两个元素组成:greeting[0]
,指向地址1000的char*
和greeting[1]
,指向地址1006的 char*
。
要获取单个字母,需要两个间接操作...
char c = greeting[1][2];
...因为获取角色是一个两个阶段的过程。首先,我们获得正确的字符串,然后从该字符串获得正确的字符。基本上,以上一行等效于...
char* p = *(greeting+1);
char c = *(p+2);
每行执行一个间接。在第一种情况下(请注意,指针是我简化的系统体系结构上的两个字节的实体),我们需要greeting
数组中的第二个成员,因此我们从地址100e读取了两个字节并获得了值1006 ,存储在p
中。在第二个中,我们需要一个位于地址p
处的char数组中的第三个成员,即1006,因此我们从地址1008中读取了一个字节并获得了值'r'。
每次添加额外的数组维时,您都将需要另一级间接(或数组索引)级别才能返回到实际数据(在这种情况下为字节)。
答案 2 :(得分:1)
我不理解您的问题,但这可能是由于对指针和数组概念的误解。
数组可以衰减到指针值,我希望示例程序可以为您提供一些示例。如您所见,多维数组以相同的间接级别衰减到指针。由于数组只是连续的内存,因此编译器将进行所有必要的地址计算
int main ()
{
char *a[] = { "11111", "22222", "33333", "44444"};
char b[][10] = { "11111", "22222", "33333", "44444"};
for(int i = 0; i < 4; i++)
{
printf("i = %d -> **(a + i) = %c ",i , **(a + i));
printf("*a[i] = %c ", *a[i]);
printf("a[i][0] = %c ", a[i][0]);
printf("*(a + i) = %s ", *(a + i));
printf("a[i] = %s\n", a[i]);
}
printf("\n\n");
for(int i = 0; i < 4; i++)
{
printf("i = %d -> **(b + i) = %c ", i, **(b + i));
printf("*b[i] = %c ", *b[i]);
printf("b[i][0] = %c ", b[i][0]);
printf("*(b + i) = %s ", *(b + i));
printf("b[i] = %s\n", b[i]);
}
return 0;
}
和结果
i = 0 -> **(a + i) = 1 *a[i] = 1 a[i][0] = 1 *(a + i) = 11111 a[i] = 11111
i = 1 -> **(a + i) = 2 *a[i] = 2 a[i][0] = 2 *(a + i) = 22222 a[i] = 22222
i = 2 -> **(a + i) = 3 *a[i] = 3 a[i][0] = 3 *(a + i) = 33333 a[i] = 33333
i = 3 -> **(a + i) = 4 *a[i] = 4 a[i][0] = 4 *(a + i) = 44444 a[i] = 44444
i = 0 -> **(b + i) = 1 *b[i] = 1 b[i][0] = 1 *(b + i) = 11111 b[i] = 11111
i = 1 -> **(b + i) = 2 *b[i] = 2 b[i][0] = 2 *(b + i) = 22222 b[i] = 22222
i = 2 -> **(b + i) = 3 *b[i] = 3 b[i][0] = 3 *(b + i) = 33333 b[i] = 33333
i = 3 -> **(b + i) = 4 *b[i] = 4 b[i][0] = 4 *(b + i) = 44444 b[i] = 44444
但是数组不是指针
这里有另一个示例显示差异。
#include <stdio.h>
char *a = "11111";
char *c = "aaaaa";
char b[] = "2222";
void foo(char **ptr, char *new)
{
*ptr = new;
}
int main ()
{
foo(&a, c);
foo(&b, c);
printf("a = %s, b = %s\n", a, b);
return 0;
}
和结果:
a = aaaaa, b = D@
您也可以尝试编译
a++;
b++;
看看编译器怎么说。