Scanf()函数读取自己的输入和下一个scanf()函数的输入。

3
我很困惑这个错误,不明白哪里出了问题。我已经进行了一些调试,但它并没有按照正确的方式执行。由于某种原因,第一个scanf()读取了两个输入,它自己的和下一个scanf()的输入。顺便说一下,我使用了%[^\n]s,因为这样它应该可以读取带有空格的字符串。我该如何修复所有问题? 代码:
#include <stdio.h>
#include <stdlib.h>

#define MAX_LEN_CODE 6
#define MAX_LEN_STRING 20

typedef struct{
    char course_code[MAX_LEN_CODE];
    char name[MAX_LEN_STRING];
    char trainer[MAX_LEN_STRING];
    int partecipants_max;
    int partecipants_num;
}t_course;

void main(){
    t_course new_course;

    system("clear");
    printf("Insert the code\n");
    printf("> ");
    scanf("%s", new_course.course_code);
    printf("Insert the name of the course\n");
    printf("> ");
    scanf(" %[^\n]s", new_course.name);
    printf("Insert the trainer\n");
    printf("> ");
    scanf("%s", new_course.trainer);
    do{
        printf("Insert the maximum number of partecipants (10-100)\n");
        printf("> ");
        scanf("%d", &new_course.partecipants_max);

        if(new_course.partecipants_max < 10 || 
        new_course.partecipants_max > 100)
            printf("ERROR: The number must be between 10 and 100!\n\n");

    }while(new_course.partecipants_max < 10 || 
        new_course.partecipants_max > 100);

    new_course.partecipants_num = 0;

    printf("\nCODE: %s\nNAME: %s\nTRAINER: %s\nPARTECIPANTS: %d\n", 
        new_course.course_code, new_course.name, 
        new_course.trainer, new_course.partecipants_max);
}

输出:

Insert the code
> aa3040
Insert the name of the course
> fitness and sport
Insert the trainer
> mario
Insert the maximum number of partecipants (10-100)
> 55

CODE: aa3040fitness and sport  // I CAN'T FIGURE OUT THIS STEP
NAME: fitness and sport
TRAINER: mario
PARTECIPANTS: 55

1
使用 fgets 获取用户输入,而不是 scanf - melpomene
顺便问一下,为什么我应该使用 int 而不是 void - reuseman
1
因为这就是 C 标准所说的。基本上可移植版本有int main(void)int main(int argc, char **argv);其他任何内容都是针对特定系统(如果你的编译器文档不支持void main,那么可能就不行)。另请参见 http://c-faq.com/ansi/maindecl.html。 - melpomene
1
为什么我总是看到 void main() {}?这种写法曾经可以接受吗? - ad absurdum
2
@AlexColucci-- 可以理解你在作业中必须使用 scanf()。如果你在 %s 中指定了最大宽度,scanf() 也可以提供一些溢出保护。但是 scanf() 很棘手且容易出错,这就是为什么你会在这里看到很多避免使用它的建议。 - ad absurdum
显示剩余2条评论
2个回答

4

您正在覆盖终止空字符的空间:

您有:

#define MAX_LEN_CODE 6

在你的t_course结构体中:
char course_code[MAX_LEN_CODE];

因此,course_code 可以存储 5 个字符+1 个终止的空字符,即 '\0' 用于标记字符串的结束,但是您提供了 6 个字符来覆盖终止的空字符的空间:

aa3040

尝试增加+1长度:

//changing MAX_LEN_CODE value:
#define MAX_LEN_CODE 7

//or instead of changing MAX_LEN_CODE
//change the size of course_code in your struct:
char course_code[MAX_LEN_CODE + 1];

或者,可以使用宽度说明符使scanf()只接受5个字符,以避免覆盖末尾的终止空字符:

scanf("%5s", new_course.course_code);

//NOTE: You still need to consume the characters left in stdin
int consume; 
while((consume = getchar()) != '\n' && consume != EOF);

2

course_code是一个由六个char字符组成的数组。它只足以存储一个长度为五个字符的NUL-terminated字符串(因为NUL占用了一个char)。由于该代码实际上是六个字符长的,NUL将存储在course_code+6处,这刚好是name中的第一个字节。因此,当您读入一个字符串到name中时,NUL将被覆盖,您最终会不知不觉地连接两个字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接