C 中的字符串数组在内存中的样子如何?

Dan*_*708 6 c arrays

我试图弄清楚 2d char 数组在内存中的样子。例如:

    char   c[][5]={"xa","ccc","bb","j","a","d"};

    printf("TEST: %u %u %u %u \n\n",c[0],*c[0],c[0]+1,*(c[0]+1));
Run Code Online (Sandbox Code Playgroud)

输出:

测试:3214246874 120 3214246875 97

c[0]=*(c+0) 是字符串“xa”,等于 3214246874,所以我猜 c[0] 是字符数组“xa”的地址。当我将 * 放入 c[0] 时,我得到 120,即 ascii 中的“x”。

所以我认为 c 数组中的第一个空格是字符 x 的地址。之后,我用 c[0]+1 尝试了同样的方法,它打印了下一个地址,然后我输入了 *,我得到了 ,97,它是 ASCII 中的“a”。

所以我假设数组 c 看起来像这样:

c[0]                              c[1]
------------------------------------------------------------------
| pointer to x | pointer to a ||| pointer to c | pointer to c | etc ...
----------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

但是我在网上搜索并没有找到任何证据来证明我的假设。

Joh*_*ger 3

您正在混淆 C 中使用的术语“字符串”的两种含义。

最正确的是,C 字符串是一个以 null 结尾的数组char。您已经声明了一个数组数组char,并使用以 null 结尾的字符序列对其进行了初始化。将其描述为“字符串数组”是完全合理的。

然而,数组与指针完全不同。您的数组的元素是其他数组,每个数组(在您的情况下)有五个chars长。这就是术语“字符串”的另一种含义的用武之地。C 数组有点难以捉摸。如果计算数组类型的(子)表达式,它将计算为指向第一个数组元素的指针。对于字符串,这样的指针具有 typechar *,因此通常将指向字符串的指针称为字符串本身。然而,这是一种口语,如果你不认识这两个相关含义之间的区别,你就会陷入麻烦。

分解您的示例代码:

    char   c[][5]={"xa","ccc","bb","j","a","d"};

    printf("TEST: %u %u %u %u \n\n",c[0],*c[0],c[0]+1,*(c[0]+1));
Run Code Online (Sandbox Code Playgroud)
  • 该表达式c[0]指定一个包含 5 个元素的数组char。当在函数调用表达式的上下文中求值时,它变成指向数组第一个元素的指针。该值的类型为char *,这不是相应printf字段描述符的正确类型%u。未定义的行为结果。您可以通过将参数转换为void *并将字段描述符更改为 来纠正此问题%p

  • 鉴于 的c[0]计算结果为指向第一个成员数组的第一个的指针char,因此表达式的*c[0]计算结果为所指向的char。该值再次与相应的字段描述符不匹配,%c您应该期望打印“x”。或者,您可以转换值:(unsigned int)*c[0]。在这种情况下,您会期望打印“x”的数字代码;很可能是 120。事实上,120 是实际打印的值,对于程序未定义行为的具体表现而言,这是一个无关紧要的特征。

  • 再次考虑到 其c[0]计算结果为指向第一个成员数组中第一个成员数组的指针char,那么接下来就是c[0] + 1一个指针加法,从而产生一个指向char该数组中第二个成员数组的指针。与 一样c[0],这与格式不匹配。

  • 想必此时我们会清楚*(c[0] + 1)计算结果为 array 中的第二个char(在索引 1 处)c[0]。该表达式严格等价于c[0][1]. 这又与格式不匹配。

所以我假设数组 c 看起来像这样 [...]

没有。该数组如下所示:

| c[0]         | c[1]         | c[2]         | c[3]         | c[4]         | c[5]         |
  x  a \0 \0 \0  c  c  c \0 \0  b  b \0 \0 \0  j \0 \0 \0 \0  a \0 \0 \0 \0  d \0 \0 \0 \0
Run Code Online (Sandbox Code Playgroud)