为什么我们使用两个间接运算符访问字符串数组

时间:2018-09-06 15:44:24

标签: c

假设

char *p;
char a[] = "Hello";

p = a;

此处 p 的地址为 a ,其指向字符串 Hello

的第一个元素

换句话说,我们需要一个间接操作符来访问字符串 Hello

的第一个元素

当我们有字符串数组时,为什么我们需要两个 Indirection 运算符,而array只是一堆具有相同数据类型的内存位置

3 个答案:

答案 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" };

然后*aa的第一个元素 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++;

看看编译器怎么说。