【问题标题】:2D array of characters, printing extra character over limit?二维字符数组,超出限制打印额外字符?
【发布时间】:2020-02-15 15:34:10
【问题描述】:

The output of code
我想创建一个字符数组,其中有“n”行,每行都有一个字符。在给定的代码中,我要求用户输入行数(n),然后创建一个变量“chr”,每行只包含一个字符。然后我逐个询问字符并将它们存储在各自的行中,但是当我打印这些字符时,会发生一些奇怪的事情。应该只存储自己的一个字符的第一行存储了不同行的所有字符。为什么?谁能给我解释一下?

#include <stdio.h>

int main(void) {
    int n;
    scanf("%d", &n);

    char chr[n][1];

    for (int i = 0; i < n; i++) {
        printf("Enter the %d character?\n", i);
        scanf("%s", chr[i]);
    }
    // printing
    for (int i = 0; i < n; i++) {
        printf("\n%s\n", chr[i]);
    }
    return 0;
}

【问题讨论】:

  • 你只为每一行分配一个字节的内存。
  • 因为您没有用空终止字节终止每个“行”,所以它将打印直到找到空字符。
  • @OldProgrammer 因为我只想从每一行中取出一个字符。
  • @fredrik 这不仅仅是关于打印。每个维度只能存储一个字符,scanf 为下一行的第一个也是唯一一个对象中的每个字符串写入终止 /0。这个例程一遍又一遍地迭代,毕竟,内存只是一大堆“切片”字符串,加上最后一个/0 超出了数组的范围。这是一个完整的未定义行为包,甚至还没有进入程序的打印部分。

标签: c arrays string character scanf


【解决方案1】:

应该只存储一个字符的第一行存储不同行的所有字符。为什么?谁能给我解释一下?

scanf("%s", chr[i]);

%s 读取整个字符串,直到遇到一个空白字符,例如换行符\n,并将其(不包括空白字符)写入第一维;不只是一个字符。

您还忘记了,因为您正在尝试读取字符串,所以 \0 会自动附加到每个字符串,但是由于 chr 的声明,一个维度中只有一个字符,而不是两个。

在内存中连续分配一个多维数组,这样就提供了这样的效果,即前一维字符串的\0字符存储在下一维的第一个也是唯一一个字符处;在下一次迭代中scanf 覆盖然后这个\0 字符以存储第二个字符,但再次将此字符串的\0 写入以下维度的第一个唯一对象,并在每次迭代中如此循环,这最终导致完全混乱的未定义行为,加上最后一个字符串的\0 超出了完整多维数组的范围。

因此,您甚至不能说它们仅存储在一个维度中,事实并非如此,即使看起来确实如此。

有关未定义行为的更多信息,请查看以下问题:

Undefined, unspecified and implementation-defined behavior


宁可使用

scanf(" %c", &chr[i][0]);

使用%c 格式说明符,每次迭代只读取一个字符,并在%cformat 说明符之前实现一个空白字符,以捕获stdin 中留下的换行符\n 由scanf 消耗上一个循环演练或任何前导空白。


另外,改变:

  for(int i = 0; i<n; i++) {
    printf("\n%s\n", chr[i]);

到

  for(int i = 0; i<n; i++) {
    printf("\n %c \n", chr[i][0]);

整个代码应该是:

#include <stdio.h>

int main(void) {

  int n;
  scanf("%d", &n);

  char chr[n][1];

  for(int i = 0; i<n; i++) {
    printf("Enter the %d character?\n", i);
    scanf(" %c", &chr[i][0]);
  }
  // printing
  for(int i = 0; i<n; i++) {
    printf("\n %c \n", chr[i][0]);
  }
return 0;
}

【讨论】:

  • @AddictedToCoding 我很高兴能帮助你。当某个答案解决了您的问题或对您最有帮助时,不要忘记将其标记为已接受的答案。
【解决方案2】:

至于回答为什么要打印其他字符,它们在内存中直接位于彼此后面,并且正如其他人指出的那样,因为您告诉它打印一个字符串,它将连续的这些字符视为一个字符串(这是一个字符数组),直到遇到终止字符。

所以在内存中这个

char array[3][1] = {{'a'},{'b'}{'c'}};

看起来像这样:

char array[3] ={'a','b','c'};

或者这个

char array[3] = {"abc"};

数组变量是指向内存中第一个字符所在地址的指针,如果使用 [],则只需将 sizeof(char) 字节数跳转到下一个字符,

与 2D 数组类似,第一个括号让你跳转 sizeof(2darray[0]) 个字节,在这种情况下与 sizeof(char) 相同,因为长度为 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-15
    • 2018-09-29
    • 1970-01-01
    • 2017-12-29
    • 2012-07-26
    • 1970-01-01
    • 2019-10-24
    • 2014-12-21
    相关资源
    最近更新 更多