为什么这个 C 代码将一个 2D 数组中的字符串与下一个一起打印出来?

noo*_*der 0 c arrays string pointers multidimensional-array

以下代码用于打印二维数组中的字符串元素。由于所有字符串中的最大长度为 5,因此我将其初始化为最大元素长度 5。

#include <stdio.h>
#include <string.h>

int main()
{
    char arr[4][5] = {"abcde", "efghi", "ijklm", "nop"};
    for(int i = 0; i < 4; i++){
        printf("String: \"%s\" with length: %d\n", arr[i], (int) strlen(arr[i]));
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但结果是

字符串:“abcdeefghiijklmnop”,长度:18
字符串:“efghiijklmnop”,长度:13
字符串:“ijklmnop”,长度:8
字符串:“nop”,长度:3

这不是想要的结果,因为我希望它们单独打印。

现在,我将数组arr可以存储的字符串的最大大小更改为 6。

#include <stdio.h>
#include <string.h>

int main()
{
    char arr[4][6] = {"abcde", "efghi", "ijklm", "nop"};
    for(int i = 0; i < 4; i++){
        printf("String: \"%s\" with length: %d\n", arr[i], (int) strlen(arr[i]));
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但现在的结果是:

字符串:“abcde”,长度:5
字符串:“efghi”,长度:5
字符串:“ijklm”,长度:5
字符串:“nop”,长度:3

这以某种方式与指针有关吗?因为我认为二维数组包含以连续方式物理存储的指针。

tst*_*isl 5

C 中的字符串实际上是char对象数组。此外,每个有效字符串必须以值为 0 的字符结尾。这个额外的 0 字节标志着字符串的结束。终止符被隐式添加到任何字符串文字中。这就是为什么"abcde"由 6 char-s组成。

在您的声明中:

char arr[4][5] = { "abcde", ... };
Run Code Online (Sandbox Code Playgroud)

字符串"abcde"char[5],所述阵列的第二维度。终止符被忽略。结果"abcde"与以下字符串合并,因为它们之间没有终止符。

现在printf("%s", arr[0])打印字符,直到找到 0 字节。这就是你看到的原因abcdeefghiijklmnop。所有字符串都合并了。

强大的修复不是使用 2D 数组,char而是使用指向常量字符串的指针数组。数组中的每个条目都是字符串实际所在的地址。

const char *arr[4] = {"abcde", "efghi", "ijklm", "nop"};
for(int i = 0; i < 4; i++)
        printf("String: \"%s\" with length: %d\n", arr[i], (int) strlen(arr[i]));
Run Code Online (Sandbox Code Playgroud)