简体   繁体   English

尝试将文件读入链接列表,但读取时程序崩溃

[英]Trying to read a file into a linked list but program crashes while reading

I've written a program to read a set of data from a file into a linked list. 我已经编写了一个程序,可以从文件中读取一组数据到一个链表中。 The program reads a line from the file, tokenizes the line, stores it into a node and then moves on to the next line. 程序从文件中读取一行,对该行进行标记,然后将其存储到节点中,然后移至下一行。 Each time it does this, I print the contents of node. 每次这样做,我都会打印节点的内容。 The issue I'm having is that when the program is run, it stops at one of two lines in the file and crashes. 我遇到的问题是程序运行时,它停在文件中的两行之一并崩溃。 It stops at one line more frequently than the other. 它比另一条停在一条线上的频率更高。

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

typedef struct prefectNode
{
    char *name; // prefect name
    char *type; // prefect type
    char *used;
    struct free// structure storing the prefect's free sessions on particular days
    {
        char M[9];
        char T[9];
        char W[9];
        char S[9];
        char F[9];
    } fses; // free sessions available to prefect;
    struct prefectNode *nextPtr;// a pointer to the next node
} pNode;// Self-Referential structure used to store information about a prefect
typedef pNode *ptrNode;// Synonym for a pointer to a self-referential structure

void induct(ptrNode *list, char l[]);// induct is called when information is being retrieved from file.

void induct(ptrNode *list, char l[])
{
    ptrNode curPtr = NULL;// pointer to the current node

    ptrNode newPtr = malloc(sizeof(pNode));// creating new node

    if (newPtr != NULL)
    {
        newPtr->name = strtok(l, ",");

        newPtr->type = strtok(NULL, ",");

        char *sesh = strtok(NULL, " ");
        char c = sesh[0];
        printf("%s\n%s\n", newPtr->name, newPtr->type);

        int i = 0, j = 0;
        for (i = 0; i < strlen(sesh); i++)
        {
            char c = sesh[i];
            if (c == 'M')
            {
                newPtr->fses.M[j] = sesh[i + 1];
                printf("M%c", newPtr->fses.M[j]);
            }
            if (c == 'T')
            {
                newPtr->fses.T[j] = sesh[i + 1];
                printf("T%c", newPtr->fses.T[j]);
            }
            if (c == 'W')
            {
                newPtr->fses.W[j] = sesh[i + 1];
                printf("W%c", newPtr->fses.W[j]);
            }
            if (c == 'S')
            {
                newPtr->fses.S[j] = sesh[i + 1];
                printf("S%c", newPtr->fses.S[j]);
            }
            if (c == 'F')
            {
                newPtr->fses.F[j] = sesh[i + 1];
                printf("F%c", newPtr->fses.F[j]);
            }

            i = i + 2;
            j++;
        }

        newPtr->nextPtr = NULL;
        curPtr = *list;

        if (curPtr == NULL)
        {
            newPtr->nextPtr = *list;
            *list = newPtr;
        }
        else
        {
            while (curPtr->nextPtr != NULL)
            {
                curPtr = curPtr->nextPtr;
            }
            curPtr->nextPtr = newPtr;
        }
    }
    else
    {
        printf("no memory");
    }
}

char ln[200];
FILE *fp;
int main()
{
    ptrNode start = NULL;

    fp = fopen("thefile.txt", "r");

    if (fp == NULL)
    {
        printf("File not found.");
    }
    else
    {
        while (!feof(fp))
        {
            fgets(ln, sizeof(ln), fp);
            induct(&start, ln);
            printf("\n\n");
        }
    }
    fclose(fp);
    getch();
    return 0;
}

This is a sample of what the input file looks like: 这是输入文件的示例:

Denelia Alvaranga,R,M7_T4_T5_T6
Sainna Christian,R,M4_M5_M6_T1_T2_T3_F5_F6
Kashielle Clarke,R,F1_T4_W4_F4_T5_W5_S5_W6_S6_M7_W7
Candice Gordon,R,M1_M2_M3_S3_T7
Alphene Groves,R,M2_T5_S7_W3
T-Anna Johnson,R,M7
Vanessa Lewis,R,M1_M2_M3_S3_T4_W4_S4_T5_S5_T6_S6

Program crashes (more frequently) when I get to line 9: 当我到达第9行时,程序崩溃(更频繁):

Rhoni-Ann Parkins,R,W1_S1_W2_S2_W3_S3_M4_T4_S4_F4_M5_T5_F5_M6_T6_F6_T7_F7

or line 37: 或第37行:

Ashleigh Graham,N6A 

Principal Problem 主要问题

One of your principal problems is that j is out of control — it is never zeroed after it is first initialized. 您的主要问题之一是j失去控制-首次初始化后,它永远不会归零。 Rhoni-Ann causes trouble because she has lots of free periods; 罗妮·安(Rhoni-Ann)遇到麻烦,因为她有很多空闲时间。 Ashleigh causes trouble because she has no free periods. Ashleigh因为没有空闲时间而引起麻烦。 With Rhoni-Ann, j gets to 18, but the arrays you're indexing only go up to 9. You need to revisit that whole portion of the code. 使用Rhoni-Ann, j可以达到18,但是要索引的数组只能达到9。您需要重新查看整个代码部分。 You need to read the number after the day letter and use that in place of the j value. 您需要阅读字母后面的数字,并用它代替j值。 You should also validate that the value is small enough (a value of 9 would cause overflows again; only 0..8 is OK), and report if the day letter is not valid. 您还应该验证该值是否足够小(值9会再次导致溢出;只有0..8是可以的),并报告日期字母是否无效。 Note too that the space is not zeroed when the memory is allocated. 还要注意,分配内存时空间不会归零。 It is not clear what you're going to do afterwards, but you don't have valid strings in the M , T , etc arrays. 目前尚不清楚您将要执行的操作,但是在MT等数组中没有有效的字符串。

Revised code 修改后的代码

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

typedef struct prefectNode
{
    char *name; // prefect name
    char *type; // prefect type
    char *used;
    struct free// structure storing the prefect's free sessions on particular days
    {
        char M[9];
        char T[9];
        char W[9];
        char S[9];
        char F[9];
    } fses; // free sessions available to prefect;
    struct prefectNode *nextPtr;// a pointer to the next node
} pNode;// Self-Referential structure used to store information about a prefect
typedef pNode *ptrNode;// Synonym for a pointer to a self-referential structure

void induct(ptrNode *list, char l[]);// induct is called when information is being retrieved from file.

void induct(ptrNode *list, char l[])
{
    ptrNode curPtr = *list; // pointer to the current node
    ptrNode newPtr = calloc(sizeof(*newPtr), 1);// creating new node

    if (newPtr != NULL)
    {
        newPtr->name = strdup(strtok(l, ","));
        newPtr->type = strdup(strtok(NULL, ","));

        printf("Prefect: %s, type %s\n", newPtr->name, newPtr->type);

        char *sesh = strtok(NULL, " ");
        if (sesh == NULL)
        {
            fprintf(stderr, "No free sessions for %s\n", newPtr->name);
            free(newPtr->name);
            free(newPtr->type);
            free(newPtr);
            return;
        }

        int i = 0, j = 0;
        int len = strlen(sesh);
        for (i = 0; i < len; i++)
        {
            char c = sesh[i];
            if (c == 'M')
            {
                newPtr->fses.M[j] = sesh[i + 1];
                printf("M%c", newPtr->fses.M[j]);
            }
            if (c == 'T')
            {
                newPtr->fses.T[j] = sesh[i + 1];
                printf("T%c", newPtr->fses.T[j]);
            }
            if (c == 'W')
            {
                newPtr->fses.W[j] = sesh[i + 1];
                printf("W%c", newPtr->fses.W[j]);
            }
            if (c == 'S')
            {
                newPtr->fses.S[j] = sesh[i + 1];
                printf("S%c", newPtr->fses.S[j]);
            }
            if (c == 'F')
            {
                newPtr->fses.F[j] = sesh[i + 1];
                printf("F%c", newPtr->fses.F[j]);
            }
            printf("(j=%d)\n", j);

            i = i + 2;
            j++;
        }

        newPtr->nextPtr = NULL;
        curPtr = *list;

        if (curPtr == NULL)
        {
            newPtr->nextPtr = *list;
            *list = newPtr;
        }
        else
        {
            while (curPtr->nextPtr != NULL)
            {
                curPtr = curPtr->nextPtr;
            }
            curPtr->nextPtr = newPtr;
        }
    }
    else
    {
        printf("no memory\n");
    }
}

static void free_node(pNode *node)
{
    if (node != 0)
    {
        free(node->name);
        free(node->type);
        free(node);
    }
}

static void free_list(pNode *node)
{
    while (node != 0)
    {
        pNode *next = node->nextPtr;
        free_node(node);
        node = next;
    }
}

static void print_sessions(const char *dow, const char *ses)
{
    printf(" %s:", dow);
    for (int i = 0; i < 9; i++)
    {
        if (ses[i] != '\0')
            printf(" %c", ses[i]);
    }
}

static void print_node(const pNode *node)
{
    printf("%s [%s]", node->name, node->type);
    print_sessions("Mon", node->fses.M);
    print_sessions("Tue", node->fses.T);
    print_sessions("Wed", node->fses.W);
    print_sessions("Thu", node->fses.S);
    print_sessions("Fri", node->fses.F);
    putchar('\n');
}

static void print_list(const char *tag, pNode *list)
{
    printf("%s:\n", tag);
    while (list != NULL)
    {
        print_node(list);
        list = list->nextPtr;
    }
}

int main(void)
{
    FILE *fp;
    char ln[200];
    ptrNode start = NULL;
    const char filename[] = "thefile.txt";

    fp = fopen(filename, "r");

    if (fp == NULL)
    {
        fprintf(stderr, "File %s not found.\n", filename);
    }
    else
    {
        while (fgets(ln, sizeof(ln), fp) != 0)
        {
            size_t len = strlen(ln);
            if (len > 0)
                ln[len-1] = '\0';
            printf("[%s]\n", ln);
            induct(&start, ln);
        }
        fclose(fp);
        print_list("After data read", start);
        free_list(start);
    }

    return 0;
}

Sample run under valgrind 样品在valgrind下运行

==54054== Memcheck, a memory error detector
==54054== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==54054== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==54054== Command: xyz
==54054== 
[Denelia Alvaranga,R,M7_T4_T5_T6]
Prefect: Denelia Alvaranga, type R
M7(j=0)
T4(j=1)
T5(j=2)
T6(j=3)
[Sainna Christian,R,M4_M5_M6_T1_T2_T3_F5_F6]
Prefect: Sainna Christian, type R
M4(j=0)
M5(j=1)
M6(j=2)
T1(j=3)
T2(j=4)
T3(j=5)
F5(j=6)
F6(j=7)
[Kashielle Clarke,R,F1_T4_W4_F4_T5_W5_S5_W6_S6_M7_W7]
Prefect: Kashielle Clarke, type R
F1(j=0)
T4(j=1)
W4(j=2)
F4(j=3)
T5(j=4)
W5(j=5)
S5(j=6)
W6(j=7)
S6(j=8)
M7(j=9)
W7(j=10)
[Candice Gordon,R,M1_M2_M3_S3_T7]
Prefect: Candice Gordon, type R
M1(j=0)
M2(j=1)
M3(j=2)
S3(j=3)
T7(j=4)
[Alphene Groves,R,M2_T5_S7_W3]
Prefect: Alphene Groves, type R
M2(j=0)
T5(j=1)
S7(j=2)
W3(j=3)
[T-Anna Johnson,R,M7]
Prefect: T-Anna Johnson, type R
M7(j=0)
[Vanessa Lewis,R,M1_M2_M3_S3_T4_W4_S4_T5_S5_T6_S6]
Prefect: Vanessa Lewis, type R
M1(j=0)
M2(j=1)
M3(j=2)
S3(j=3)
T4(j=4)
W4(j=5)
S4(j=6)
T5(j=7)
S5(j=8)
T6(j=9)
S6(j=10)
[Rhoni-Ann Parkins,R,W1_S1_W2_S2_W3_S3_M4_T4_S4_F4_M5_T5_F5_M6_T6_F6_T7_F7]
Prefect: Rhoni-Ann Parkins, type R
W1(j=0)
S1(j=1)
W2(j=2)
S2(j=3)
W3(j=4)
S3(j=5)
M4(j=6)
T4(j=7)
S4(j=8)
F4(j=9)
M5(j=10)
T5(j=11)
F5(j=12)
M6(j=13)
T6(j=14)
F6(j=15)
T7(j=16)
F7(j=17)
[Ashleigh Graham,N6A ]
Prefect: Ashleigh Graham, type N6A 
No free sessions for Ashleigh Graham
After data read:
Denelia Alvaranga [R] Mon: 7 Tue: 4 5 6 Wed: Thu: Fri:
Sainna Christian [R] Mon: 4 5 6 Tue: 1 2 3 Wed: Thu: Fri: 5 6
Kashielle Clarke [R] Mon: Tue: 7 4 5 Wed: 4 5 6 Thu: 7 5 6 Fri: 1 4
Candice Gordon [R] Mon: 1 2 3 Tue: 7 Wed: Thu: 3 Fri:
Alphene Groves [R] Mon: 2 Tue: 5 Wed: 3 Thu: 7 Fri:
T-Anna Johnson [R] Mon: 7 Tue: Wed: Thu: Fri:
Vanessa Lewis [R] Mon: 1 2 3 Tue: 4 5 Wed: 6 4 Thu: 3 4 5 Fri: 6
Rhoni-Ann Parkins [R] Mon: 4 Tue: 5 6 4 Wed: 1 5 3 6 7 Thu: 1 2 3 4 Fri:
==54054== 
==54054== HEAP SUMMARY:
==54054==     in use at exit: 26,297 bytes in 186 blocks
==54054==   total heap usage: 297 allocs, 111 frees, 37,503 bytes allocated
==54054== 
==54054== LEAK SUMMARY:
==54054==    definitely lost: 0 bytes in 0 blocks
==54054==    indirectly lost: 0 bytes in 0 blocks
==54054==      possibly lost: 0 bytes in 0 blocks
==54054==    still reachable: 0 bytes in 0 blocks
==54054==         suppressed: 26,297 bytes in 186 blocks
==54054== 
==54054== For counts of detected and suppressed errors, rerun with: -v
==54054== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

The 'suppressed' memory is an artefact of running on Mac OS X (10.11.3). “被抑制”的内存是在Mac OS X(10.11.3)上运行的产物。 I'm using GCC 5.3.0. 我正在使用GCC 5.3.0。 The code is clean — it releases all the memory it allocates. 代码很干净—释放了分配的所有内存。 (That's what the zeros for 'definitely lost', 'indirectly lost', 'possibly lost', and 'still reachable' mean.) (这就是“绝对丢失”,“间接丢失”,“可能丢失”和“仍然可以到达”的零。)

Note that despite using valgrind , it is not complaining about 'out of bounds' memory accesses, but you can see that j is printed and reaches 'j=17' for Rhoni-Ann. 请注意,尽管使用了valgrind ,但它并没有抱怨“超出范围”的内存访问,但是您可以看到j的打印已显示,并且达到Rhoni-Ann的“ j = 17”。 You're definitely not writing where you intended — the output for each prefect does not match your input, because j is out of control. 您绝对不是在写您想要的位置—每个j的输出与您的输入都不匹配,因为j失控了。 It so happens that when you write to newPtr->fses.F[j] with j set to 17 on a 64-bit system, you are still within bounds of the memory allocated because the struct free occupies 45 bytes, but is padded to 48 bytes to align the 8-byte pointer nextPtr , so F[17] is within the pointer (which you subsequently over-write). 碰巧的是,当您在64位系统上将j设置为17写入newPtr->fses.F[j] ,由于struct free占用45个字节,但您仍处于分配的内存范围之内,但被填充为48个字节以对齐8个字节的指针nextPtr ,因此F[17]在指针内(您随后将其覆盖)。 If you are compiling with a 32-bit compiler, the story might be different. 如果使用32位编译器进行编译,则情况可能有所不同。 (I got some 'Conditional jump or move depends on uninitialised value(s)' errors, but not an 'out of bounds' write as I expected.) (我遇到了一些“有条件的跳转或移动取决于未初始化的值”错误,但没有像我预期的那样“超出范围”写。)

Other problems: 其他问题:

  • See [ while (!feof(file)) is always wrong] for why your input loop is flawed. 请参阅[ while (!feof(file))总是错误的],以了解您的输入循环有缺陷的原因。
  • You shouldn't try to close the file if you failed to open it. 如果打开文件失败,则不要尝试关闭该文件。
  • You should report errors to stderr , not stdout . 您应该将stderr报告给stderr ,而不是stdout
  • You should end messages with newlines so that they're seen. 您应该以换行符结束消息,以便可以看到它们。
  • Both fp and ln should be local variables in main . fpln都应该是main局部变量。
  • You overwrite the names you store because you don't make a copy of the strings for inclusion in the structure — they all point to the array ln . 您覆盖存储的名称是因为您没有复制要包含在结构中的字符串-它们都指向ln数组。
  • You don't set the used element to a known value. 您无需将used元素设置为已知值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM