为什么scanf();会跳过第一行?

问题描述 投票:0回答:2

所以在scanf()之后的 printf(); 跳过第一行,我读过一些问题,告诉。 "%[^\n]" 必须 " %[^\n]" 来跳过换行。 我已经尝试了这两种方法,但还是打印出同样的结果,现在我不知道为什么它不工作。

Example input
Enter number of Materi: 4
Materia 1 name : a
Materia 2 name : b
materia 3 name : c
materia 4 name : d

Output:
Materia - 1 : R╒fu
Materia - 2 : a
Materia - 3 : b
Materia - 4 : c
#include<stdio.h>
#include<windows.h>

int main(int argc, const char *argv[]){

    int i;
    int V;

    printf("Enter number of Materi: ");
    scanf("%d", &V); fflush(stdin);

    //Insert materia
    char materia[V][50];
    for(i = 0; i < V; i++){
        printf("Materia %d name : ", i+1);scanf("%[^\n]", &materia[i][50]);fflush(stdin);
    }

    for(i = 0; i < V; i++){
        printf("Materia - %d: %s\n", i+1, materia[i]);
    }
    system("pause");

    return 0;
}


c string scanf
2个回答
3
投票

有几个错误的程序

  • 传递给 scanf 是错误的。

  • fflush(stdin) 是非标准的,虽然Windows确实支持它,但它不具备可移植性。但你没有使用Windows,因为它不支持VLA------。char materia[V][50];

  • 的新行。scanf 格式化 "%[^\n]" 将停止在,已经是输入缓冲区的下一个字符。

  • 的返回值,已经是输入缓冲区中的下一个字符。scanf 没有被检查。它是成功扫描的项目数量。

  • 因为输入的字符串长度不受限制,所以可以出现缓冲区溢出。

下面是调整后的代码。

#include<stdio.h>

int main(int argc, const char *argv[]){

    int i;
    int V;

    printf("Enter number of Materi: ");
    if(scanf("%d", &V) != 1) {
        /* add some error message */
        return 1;
    }
    // fflush(stdin);               // removed

    //Insert materia
    char materia[V][50];
    for(i = 0; i < V; i++){
        printf("Materia %d name : ", i+1);
        // add a space to filter the newline
        // correct the array passed
        // and restrict the length to prevent buffer overflow
        if(scanf(" %49[^\n]", materia[i]) != 1) {
            /* add some error message */
            return 1;
        }
        // fflush(stdin);           // removed
    }

    for(i = 0; i < V; i++){
        printf("Materia - %d: %s\n", i+1, materia[i]);
    }

    return 0;
}

关于换行。格式规格 %d%s%f 自动过滤掉前导空格,但 %c%[]%n 没有。的。scanf 函数停止在它们不能转换的第一个字符上,即留在输入缓冲区中。缓冲区中的 %[^\n] 叫它停在第一个新行。但那里已经有一个了,从第一个新行开始。%d scanf,它需要被移除,也是在后续的迭代中,添加空间就可以完成这个工作。之后再想删除它是很笨拙的,而且不保证能成功。

你必须检查 scanf 每次使用时。它是成功扫描的项目数量。这里,它应该是 1 在两个用途中。因此,如果你在一条语句中包含两个项目,它的返回值必须是 2.


1
投票

在这一行中。

scanf("%[^\n]", &materia[i][50]); 

你把输入的字符串存储在了地址为 materia[i][50],有效地将其存储在数组的边界之外。

这里发生了一些有趣的事情,二维数组的存储是连续的,就像它是一个一维向量一样,发生的事情是你把第一个字符串存储在数组第二行的开头,第二个存储在第三行,以此类推,留下第一个空。这就是程序产生输出的合理性。

纠正你的代码与。

#include<stdlib.h>

//...

if(scanf(" %49[^\n]", materia[i] != 1) {
   puts("Read error");
   return EXIT_FAILURE;       
}

49个字符+nul结束符以避免溢出, 在指定符的开头加一个空格以避免占用空字符 stdin 缓冲区。始终验证 scanf 返回,以避免阅读错误。

其他一些问题。

  • fflush(stdin) 应删除为 fflush 是为了在输出流上调用.

  • 如果消耗了足够的内存,可变长度的数组可能会导致堆栈溢出,在这种情况下,它的可能性不大,但这是需要注意的。


0
投票

使用 fgets 而不是 scanf. 新行字符会被您后续的 scanf. 这就是为什么你面临这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.