【问题标题】:Linked Lists and fscanf链表和 fscanf
【发布时间】:2015-06-09 18:39:12
【问题描述】:

我正在尝试创建一个链接列表来存储来自文本文件的输入。 我可以获取第一组信息,但是当我获取后续信息时,出现了段错误。

请告诉我我做错了什么。

这是我的全部代码

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int CourseID;
    char CourseName[30];
 } courseInfo;

struct StudentInfo{
    char StudentID[9];
    char FirstName[20];
    char LastName[25];
    int Courses;
    courseInfo CourseInfo[10];
    struct StudentInfo *next; 

};
typedef struct StudentInfo studentInfo;
typedef studentInfo *ListPtr;

studentInfo LoadFile(studentInfo *RootPtr);
void PrintStruct(studentInfo *startPtr);

int main()
{
studentInfo studentList[100];
ListPtr HeadPtr = NULL;
printf("Loading File...\n");

LoadFile(HeadPtr);
printf("Load Success\n");
PrintStruct(studentList);
printf("AfterPrint\n");


return 0;
}
studentInfo LoadFile( studentInfo *RootPtr)
{
FILE * ptrFile;

ListPtr NodePtr = malloc(sizeof (studentInfo));
ListPtr curr;
int counter, i=0;


ptrFile = fopen("studentInfo.txt", "r");

if( ptrFile == NULL)
    printf("Open Unsuccessful\n");

fscanf(ptrFile,"%s", NodePtr->StudentID);
printf("%s\n", NodePtr->StudentID);
fscanf(ptrFile,"%s", NodePtr->FirstName);
printf("%s\n", NodePtr->FirstName);
fscanf(ptrFile,"%s", NodePtr->LastName);
printf("%s\n", NodePtr->LastName);
fscanf(ptrFile,"%d", &(NodePtr->Courses));
printf("%d\n", NodePtr->Courses);

for(counter = 0; counter <= NodePtr->Courses; counter++)
{
    fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName);
    printf("%s ", NodePtr->CourseInfo[counter].CourseName);
    fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID));
    printf("%d\n", NodePtr->CourseInfo[counter].CourseID);

}   
curr = RootPtr;
NodePtr->next = NULL;
RootPtr = NodePtr;
NodePtr = NodePtr -> next;

while( strcmp("***", NodePtr->StudentID) !=0 )
{

    fscanf(ptrFile,"%s", NodePtr->StudentID);
    printf("%s\n", NodePtr->StudentID);

    fscanf(ptrFile,"%s", NodePtr->FirstName);
    printf("%s\n", NodePtr->FirstName);

    fscanf(ptrFile,"%s", NodePtr->LastName);
    printf("%s\n", NodePtr->LastName);

    fscanf(ptrFile,"%d", &(NodePtr->Courses));
    printf("%d\n", NodePtr->Courses);

        for(counter = 0; counter <= NodePtr->Courses; counter++)
        {
            fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName);
            printf("%s ", NodePtr->CourseInfo[counter].CourseName);
            fscanf(ptrFile,"%d",&(NodePtr->CourseInfo[counter].CourseID));
            printf("%d\n", NodePtr->CourseInfo[counter].CourseID);

        }
    NodePtr = NodePtr->next;
}
fclose(ptrFile);


return *NodePtr;
}
void PrintStruct(studentInfo *startPtr)
 {
int i;
ListPtr begin;
printf("In print\n");
for( begin = startPtr; begin->next != NULL; begin=begin->next)
{
    printf("%s\n", begin->StudentID);
    printf("%s\n", begin->FirstName);
    printf("%s\n", begin->LastName);
    printf("%d\n", begin->Courses);
    for(i = 0; i <= begin->Courses; i++)
    {   
        printf("%s", begin->CourseInfo[i].CourseName);
        printf("%d\n", begin->CourseInfo[i].CourseID);
    }

}

return;
 }

`

我的文本文件是: 111111111 丽莎 搬运工 3 ENEE 114 CMSC 412 恩梅 515 333333333 亚历克斯 辛普森 1 CMSC 412


并且最多只能打印“333333333” 后跟一个“0”,然后是一个段错误。

【问题讨论】:

  • 无关:在printf("Open Unsuccessful\n");之后你应该退出。

标签: c file linked-list scanf


【解决方案1】:

对字符串输入扫描到不足的缓冲区没有限制。

以下尝试将“111111111”存储到char 数组中。第一个是 9 个char,其中fscanf(ptrFile,"%s",...) 扫描并存储到NodePtr-&gt;StudentID - 9 个char 数组中。然后 fscanf 附加一个 '\0' 并在调用未定义行为 (UB) 的数组外部写入。

struct StudentInfo{
  char StudentID[9];
...
// My text file is : 111111111 Lisa Porter 3 ENEE 114 CMSC 4
fscanf(ptrFile,"%s", NodePtr->StudentID);

代码应该 1) 分配足够的空间 2) 使用 "%9s" 限制输入长度和 3) 检查 fscanf() 结果。更好:

struct StudentInfo{
  // Enough space for 9 char and \0
  char StudentID[9+1];
...
// add if and ------------v
if (1 != fscanf(ptrFile,"%9s", NodePtr->StudentID)) 
  Handle_Error();

【讨论】:

    【解决方案2】:

    读取文件时存在一些问题,正如 valgrind 所强调的那样:

    $ valgrind ./a.out          
    ==4662== Memcheck, a memory error detector
    ==4662== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==4662== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
    ==4662== Command: ./a.out
    ==4662== 
    Loading File...
    111111111
    Lisa
    Porter
    3
    ENEE 114
    CMSC 412
    ENME 515
    ==4662== Conditional jump or move depends on uninitialised value(s)
    ==4662==    at 0x4E7BA91: vfprintf (vfprintf.c:1635)
    ==4662==    by 0x4E855C8: printf (printf.c:33)
    ==4662==    by 0x400A09: LoadFile (bar.c:66)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662== 
    ==4662== Use of uninitialised value of size 8
    ==4662==    at 0x4E7B0FB: _itoa_word (_itoa.c:179)
    ==4662==    by 0x4E7EB02: vfprintf (vfprintf.c:1635)
    ==4662==    by 0x4E855C8: printf (printf.c:33)
    ==4662==    by 0x400A09: LoadFile (bar.c:66)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662== 
    ==4662== Conditional jump or move depends on uninitialised value(s)
    ==4662==    at 0x4E7B105: _itoa_word (_itoa.c:179)
    ==4662==    by 0x4E7EB02: vfprintf (vfprintf.c:1635)
    ==4662==    by 0x4E855C8: printf (printf.c:33)
    ==4662==    by 0x400A09: LoadFile (bar.c:66)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662== 
    ==4662== Conditional jump or move depends on uninitialised value(s)
    ==4662==    at 0x4E7EB4E: vfprintf (vfprintf.c:1635)
    ==4662==    by 0x4E855C8: printf (printf.c:33)
    ==4662==    by 0x400A09: LoadFile (bar.c:66)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662== 
    ==4662== Conditional jump or move depends on uninitialised value(s)
    ==4662==    at 0x4E7BB5C: vfprintf (vfprintf.c:1635)
    ==4662==    by 0x4E855C8: printf (printf.c:33)
    ==4662==    by 0x400A09: LoadFile (bar.c:66)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662== 
    ==4662== Conditional jump or move depends on uninitialised value(s)
    ==4662==    at 0x4E7BBDF: vfprintf (vfprintf.c:1635)
    ==4662==    by 0x4E855C8: printf (printf.c:33)
    ==4662==    by 0x400A09: LoadFile (bar.c:66)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662== 
    333333333 0
    ==4662== Invalid read of size 1
    ==4662==    at 0x4C2D1D3: strcmp (vg_replace_strmem.c:755)
    ==4662==    by 0x400A5A: LoadFile (bar.c:74)
    ==4662==    by 0x400784: main (bar.c:30)
    ==4662==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    

    更具体地说,我建议您使用scanfassert 来确保读取了一个值(如果没有要读取的内容,scanf 可能会在不设置变量的情况下返回):

        assert(1 == fscanf(ptrFile,"%s", NodePtr->CourseInfo[counter].CourseName));
        printf("%s ", NodePtr->CourseInfo[counter].CourseName);
        assert(1 == fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID)));
        printf("%d\n", NodePtr->CourseInfo[counter].CourseID);
    

    (也包括assert.h

    现在,如果你执行你的程序,你会得到:

    $ valgrind ./a.out           
    ==4750== Memcheck, a memory error detector
    ==4750== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==4750== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
    ==4750== Command: ./a.out
    ==4750== 
    Loading File...
    111111111
    Lisa
    Porter
    3
    ENEE 114
    CMSC 412
    ENME 515
    a.out: bar.c:66: studentInfo LoadFile(studentInfo *): Assertion `1 == fscanf(ptrFile,"%d", &(NodePtr->CourseInfo[counter].CourseID))' failed.
    

    所以这确实是问题所在:您的程序尝试在文件结束后读取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 2018-06-21
      • 2015-09-25
      • 2019-04-27
      相关资源
      最近更新 更多