scanf() 不写入二维字符数组

Stu*_*art 2 c runtime-error scanf c-strings multidimensional-array

我正在阅读一本教科书,使用 Code::Blocks v20.03 IDE 自学 C 编程。

我真的被一个小程序迷惑了,该程序将三个小字符串读入一个二维字符数组,然后将它们打印到屏幕上。该程序的代码如下所示。

#include <stdio.h>

int main(void)
{
   char *colors[3][10] = {'\0'};

   printf("\nEnter 3 colors seperated by spaces: ");
   scanf("%s %s %s", colors[0][0], colors[1][0], colors[2][0]);

   printf("\nYour entered: ");
   printf("%s %s %s\n", colors[0][0], colors[1][0], colors[2][0]);
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译时错误或警告为零,执行时会产生以下输出。

您输入:(空)(空)(空)

使用 IDE 的 Watches 窗口显示没有任何内容写入数组。我知道数组名称被视为指向数组中第一个元素的指针。我还了解使用下标/索引来访问数组维度内的元素(例如整数数组),因此需要将这个 char 数组中的数组第二维保持为零。

可悲的是,这让我完全困惑,所以我需要帮助来填补我的理解空白。

此致,

斯图尔特

And*_*zel 5

scanf与说明符一起使用时%s,必须提供一个指向要scanf写入的内存地址的指针。因此,您必须首先创建一个内存缓冲区,该缓冲区有足够的空间来存储整个字符串。最简单的方法是声明一个类型为 的数组char

然而,该行

char *colors[3][10] = {'\0'};
Run Code Online (Sandbox Code Playgroud)

不会声明类型为 的数组char。相反,它将创建一个多维指针数组。

如果你想创建一个类型为 的数组char,你可以这样做:

char color[10];
Run Code Online (Sandbox Code Playgroud)

如果要创建 类型的数组的数组char,可以这样做:

char colors[3][10];
Run Code Online (Sandbox Code Playgroud)

现在您可以使用该行

scanf( "%s %s %s", colors[0], colors[1], colors[2] );
Run Code Online (Sandbox Code Playgroud)

这相当于

scanf( "%s %s %s", &colors[0][0], &colors[1][0], &colors[2][0] );
Run Code Online (Sandbox Code Playgroud)

由于数组到指针的衰减。在大多数情况下,如果在表达式中使用数组的名称,它将衰减为指向数组第一个元素的指针。

请注意,使用%s是危险的,因为如果用户键入的数据超出了内存缓冲区的容纳范围(在本例中超过 9 个字符),那么就会出现缓冲区溢出,从而导致未定义的行为

因此,这样写会更安全:

scanf( "%9s %9s %9s", colors[0], colors[1], colors[2] );
Run Code Online (Sandbox Code Playgroud)

这将匹配的字符数限制为9每个字符串的字符数,因此scanf永远不会将超过的10字符(9字符加上终止空字符)写入内存缓冲区。