【问题标题】:Last element is missing from the 2D array二维数组中缺少最后一个元素
【发布时间】:2020-02-11 19:18:03
【问题描述】:

代码:

#include <stdio.h>


 int main(){

    int num;

    scanf("%d", &num);
    printf("Enter: ");

    char nums[5][num], ch;

    for(int i = 0; i < num; i++){
        for(int j = 0; j < 5; j++){
            if((ch = getchar()) != '\n'){
                nums[j][i] = ch;
            }
        }
    }


    for(int i = 0; i < num; i++){
        for(int j = 0; j < 5; j++){
            printf("%c ", nums[j][i]);
        }
        printf("\n");
    }

    return 0;
 }

输出:

1
Enter: 12345
 1 2 3 4 

Process returned 0 (0x0)   execution time : 6.282 s
Press ENTER to continue.

为什么最后一个元素不见了,而数组输出的开头又多了一个空格?

如果我将两个 for 循环中 j 的范围更改为

j <= 5

然后,输出如下所示:

1
Enter: 12345
 1 2 3 4 5 

Process returned 0 (0x0)   execution time : 2.107 s
Press ENTER to continue.

如果在 printf 循环中 j 的初始值为 1,则输出如下所示:

1
Enter: 12345
1 2 3 4 5 

Process returned 0 (0x0)   execution time : 3.675 s
Press ENTER to continue.

在数组输出的开头没有多余的间隙。

谁能解释一下这个问题以及如何解决这个问题?

【问题讨论】:

  • 您的第一个 getchar 正在使用 scanf 留下的换行符。将其替换为 scanf("%d ", &amp;num);(注意空格)。
  • 一般情况下,您应该避免将scanf与其他输入法一起使用。如果您使用scanf 读取数字(使用"%d"),那么您应该使用scanf 读取字符(使用" %c")。注意%c之前的空格。
  • @EugeneSh。 scanf 中的尾随空格是个坏主意,这意味着输入将阻塞,直到他们键入另一个非空白项
  • 通常,在 C 中,如果你有一个二维数组 SomeType array[5][num];,你的循环将在尾随索引之前的前导索引上工作:for (int i = 0; i &lt; 5; i++) { for (int j = 0; j &lt; num; j++) { …array[i][j]… },但你的代码可以使用索引其他方式 - 所以你填充列而不是行。这不是自动错误的,但它在 C 中是不常见的(尽管 Fortran 的工作方式)。您可以查找“列主要”和“行主要”索引 - 例如,请参阅 Wikipedia on Row-Major and Column-Major Order

标签: c multidimensional-array 2d fflush


【解决方案1】:

问题在于函数getchar从输入流中读取所有字符,包括第一次调用scanf后存储在缓冲区中的换行符。

所以在循环中读取的第一个字符是换行符'\n'。 例如,您应该通过以下方式将其删除。

scanf( "%*[^\n]" );
scanf( "%*c" );

【讨论】:

  • 另一种方法,虽然不那么优雅,但是在scanf 之后添加类似while(getchar() != '\n') continue; 的内容。
  • @FiddlingBits 虽然你也应该检查 EOF
  • 换句话说,对 scanf 的第一次调用是读取 char "1" 并且有 \n 潜伏在输入缓冲区中。接下来,你开始调用 getchar(),所以你得到\n 1 2 3 4,所以这些是你正在阅读的 5 个元素。 '5' 不会被读取,因为您硬编码了对 getchar() 的 5 个调用
【解决方案2】:

您在第一个循环中存在逻辑问题。您测试\n,但如果您确实找到\n,您将保持数组条目未初始化并继续进行下一个条目。这会导致虚假输出。

相反,您可以延迟 j++ 直到获得有效字符,例如:

for(int i = 0; i < num; i++){
    for(int j = 0; j < 5;     ){
        if((ch = getchar()) != '\n'){
            nums[j][i] = ch;
            ++j;
        }
    }
}

然后数组将被输入的非换行符填充,您不需要进行任何其他刷新。

它会改进代码来检查ch != EOF(并且ch应该声明为int),但是你需要一些错误处理(如果只是打破循环并继续下去是错误的尝试输出整个数组)。

【讨论】:

    猜你喜欢
    • 2017-08-11
    • 1970-01-01
    • 2016-09-23
    • 1970-01-01
    • 2018-08-06
    • 2021-03-04
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    相关资源
    最近更新 更多