Scanf总是跳过第二行输入

Scanf总是跳过第二行输入,c,struct,linked-list,scanf,C,Struct,Linked List,Scanf,我正在尝试读取文本数据行,并将它们存储在链接列表中。 输入数据如下所示: David Copperfield Charles Dickens 4250 24.95 32.95 10 6 END_DATA 我读取数据的方法是首先读取第一行,看看它是否是END_数据。如果不是,那么我将第一行传递给一个函数,该函数创建一个包含书籍数据的链表节点。出于某种原因,在我将第一行传递给函数后,scanf不会读取第二行 当我尝试在节点读取数据后打印节点时,我的输出如下所示 David Copperfield

我正在尝试读取文本数据行,并将它们存储在链接列表中。 输入数据如下所示:

David Copperfield
Charles Dickens
4250
24.95
32.95
10
6
END_DATA
我读取数据的方法是首先读取第一行,看看它是否是END_数据。如果不是,那么我将第一行传递给一个函数,该函数创建一个包含书籍数据的链表节点。出于某种原因,在我将第一行传递给函数后,scanf不会读取第二行

当我尝试在节点读取数据后打印节点时,我的输出如下所示

David Copperfield 

0 
0.000000 
0.000000 
0 
0
Charles Dickens 

4250 
24.950001 
32.950001 
10 
6
Charles Dickens 

0 
0.000000 
0.000000 
0 
0
源代码如下

#include "lab3p1.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


struct NodeRec {
    Book data;
    struct NodeRec *next;
};

typedef struct NodeRec Node;

float findRevenue(Node *head);
float totalWholesaleCost(Node *head);
float totalProfit(Node *head);
float totalBooksSold(Node *head);
float averageProfitPerSale(Node *head);
void printNodes(Node *head);

void insertNode(Node* head, Node* newNode);

Node* createNewNode(char titleS[40]) {
    Node* newNode;
    newNode = malloc(sizeof(Node));
    if (newNode == NULL){
        printf("ERROR ALLOCATING SPACE");
        exit(-1);
    }
    else {
        strcpy(newNode->data.title, titleS);
        scanf("%40[^\n]*c", (char *)&newNode->data.author);

        scanf ("%i %f %f %i %i", &newNode->data.number, &newNode->data.wholesaleprice, &newNode->data.retailprice, &newNode->data.wholesalequantity, &newNode->data.retailquantity);

        printf ("%s \n%s \n%i \n%f \n%f \n%i \n%i\n", newNode->data.title, newNode->data.author,newNode->data.number, newNode->data.wholesaleprice, newNode->data.retailprice, newNode->data.wholesalequantity, newNode->data.retailquantity);

    }

    return newNode;
}


void readBooks(Node* head) {

    char firstline[40];
    char enddataString[40] = "END_DATA";
    scanf("%40[^\n]*c", (char *)&firstline);


    while (strcmp(firstline, enddataString)) {

        Node* newNode = createNewNode(firstline);
        insertNode(head, newNode);

        scanf("%40[^\n]*c", (char *)&firstline);
    }
}



void insertNode(Node* head, Node* newNode) {

    if (head == NULL) {
        head = newNode;
    }
    else {
        Node *preNode, *currentNode;

        int n = newNode->data.number;
        currentNode = head;

        while (currentNode != NULL && (currentNode->data.number) > n ) {
            preNode = currentNode;
            currentNode = currentNode->next;

        }
        newNode->next = currentNode;
        preNode->next = newNode;
    }
}
#包括“lab3p1.h”
#包括
#包括
#包括
结构节点{
图书资料;
结构NodeRec*下一步;
};
typedef结构节点Rec节点;
浮点数地点(节点*头部);
浮动批发总成本(节点*头);
浮动总利润(节点*头);
浮动总销售额(节点*头部);
浮动平均利润率(节点*头);
无效打印节点(节点*头部);
void insertNode(节点*头,节点*新节点);
节点*createNewNode(字符标题[40]){
节点*新节点;
newNode=malloc(sizeof(Node));
if(newNode==NULL){
printf(“分配空间错误”);
出口(-1);
}
否则{
strcpy(newNode->data.title,titleS);
scanf(“%40[^\n]*c”,(char*)&newNode->data.author);
scanf(“%i%f%f%i%i”、&newNode->data.number、&newNode->data.whistalprice、&newNode->data.retailprice、&newNode->data.whistalquantity、&newNode->data.whistalquantity、&newNode->data.retailquantity);
printf(“%s\n%s\n%i\n%f\n%f\n%n%i\n”,newNode->data.title,newNode->data.number,newNode->data.whistalprice,newNode->data.retailprice,newNode->data.retailprice,newNode->data.whistalequantity,newNode->data.retailquantity);
}
返回newNode;
}
无效读本(节点*头){
第一行字符[40];
char enddataString[40]=“END_DATA”;
scanf(“%40[^\n]*c”,(char*)和firstline);
while(strcmp(第一行,enddataString)){
Node*newNode=createNewNode(第一行);
插入节点(头,新节点);
scanf(“%40[^\n]*c”,(char*)和firstline);
}
}
void insertNode(节点*头,节点*新节点){
if(head==NULL){
头=新节点;
}
否则{
节点*preNode,*currentNode;
int n=newNode->data.number;
currentNode=头部;
而(currentNode!=NULL&&(currentNode->data.number)>n){
preNode=当前节点;
currentNode=currentNode->next;
}
newNode->next=currentNode;
preNode->next=newNode;
}
}

问题在于您的scanf格式字符串。在以下行中存在一些问题:

scanf("%40[^\n]*c", (char *)&firstline);
首先,您希望阅读到行尾的所有内容(40个字符或更少)<代码>%40[^\n]将执行此操作。但是不需要
c
。。括号内的表达式取代了它。。因此,scanf可能只是在输入中寻找一个普通字符“c”。。不是你想要的,这会给你带来麻烦。星号在这个位置上也没有我所知道的意义

第二个问题是,由于您告诉scanf仅使用换行符之前的字符,因此换行符仍保留在stdin缓冲区中等待使用。由于下一个scanf也拒绝使用换行符,因此它将完全不使用任何内容。使用scanf时,必须将格式字符串设计为指定或放弃输入中的每个字符,否则解析将失败

将此替换为:

scanf("%40[^\n] ", (char *)&firstline);
…你的计划会成功的。这也应该在您的作者scanf调用中使用。这里的格式字符串基本上表示“读取所有不是换行符的内容..直到看到换行符或得到40个字符。然后跳过看到的任何空白”。这将消耗stdin直到下一行的第一个字符,这是您想要的

但基本上,scanf是一个熊,很难正确使用,这就是为什么它很少用于这种事情了。我从不使用它。例如,您是否考虑过如果作者或标题包含超过40个字符,程序中会发生什么情况?scanf的手册页上说

当达到此最大值或 当找到不匹配的字符时,以先发生的为准

这意味着未读的字符将保留在缓冲区中,并破坏对所有剩余行的解析

当然,可以设计一种scanf格式来处理它。。你必须将其设置为除换行外的所有内容,然后将其扔掉。。然后留下最后的空间来使用换行符。我现在不能让那个部件工作。。但你应该:)

另一个主要问题是空终止符。首先,每个字符串都必须以null结尾,scanf
c
格式说明符的手册页会显示

..下一个指针必须是指向char的指针,并且必须有足够的 容纳所有字符的空间(不添加终止空字节)

所以,如果您告诉scanf读取40个字符,那么指向存储的指针最好指向至少41个!例如:

char author[41];
空终止是你的问题!而你却没有这样做。。这将导致一场车祸。你现在真的很幸运

快速解决空终止符问题的一种方法是使用calloc()来分配节点,而不是malloc()。使用calloc()时,您的内存将被从开始到结束的所有空字节填满

不管怎样,我想你现在已经有足够的时间继续下去了。如果我是你,我会探索使用fgets()分别读取输入中的每一行,然后使用各种解析函数获取值。。例如,我需要解析整数。它需要更多的工作,但最终更可靠,更容易理解。如果您坚持使用scanf,您必须真正阅读该手册页,并尝试可视化输入中的每个字符将如何使用或不使用。另外,确保每个字符串都是y