fscanf到一个链表

时间:2014-12-03 10:03:05

标签: c linked-list malloc

我的代码再次出现问题 我想fscanf result.txt到带有链表的结构,但它不起作用; 我认为必须使用简单的链表;

问题是:程序只写第一行,但没有别的。

result.txt格式:

point name (for examples)
623   john
457   peter
312   chuck
etc.

代码:

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

    typedef struct ranklist {
        int point;
        char* name;
        struct ranklist *next;
    } ranklist;

    int how_many_records(FILE *fp){
        char ch;
        int line=0;
        int status;

        rewind(fp);
        while((status=fscanf(fp, "%*d %*[^\n]%c", &ch))==1)
            ++line;
        if(status != EOF){
            ++line;
        }
        rewind(fp);

        return line;
    }

    int how_many_letter(FILE *fp){
        int letter = 0;
        long pos = ftell(fp);

        //fscanf(fp, " %*[^\n]%n", &letter);
        fscanf(fp, " %*s%n", &letter);
        fseek(fp, pos, SEEK_SET);

        return letter;
    }

    int main(void){
        FILE *fp = fopen("result.txt","r");
        int name_length;
        int lines = how_many_records(fp);
        ranklist *r = malloc(lines * sizeof(*r));
        ranklist *first = r;


        for ( r=first  ;r != NULL; r = r->next){
            fscanf(fp, "%d", &(r->point));
            name_length = how_many_letter(fp);
            r->name = malloc(name_length + 1);
            fscanf(fp,"%s", r->name);
        }

        fclose(fp);

        for ( r=first  ;r != NULL; r = r->next){
            printf("%d %s\n", r->point, r->name);
        }
        free(r);

        return 0;
    }

3 个答案:

答案 0 :(得分:0)

fscanf(fp, "%d", &r[y].point);

此处,y未初始化。

您需要将y = 0或IMO更好地用于&(r->point) [同样适用于r[y].name]

建议:更好地阅读和解析整行以使用fgets()

答案 1 :(得分:0)

创建列表时遇到了多个问题。

让我们从循环开始:

for ( r=first  ;r != NULL; r = r->next){
循环中的

无处会初始化r->next,因此在第一次迭代后,您将y指向完全随机的内存,从而导致undefined behavior

正如另一个答案中所提到的,你不要初始化变量y,这是导致未定义行为的另一个原因。

您还更改 r,因此r不会指向您分配的原始内存,因此r[y]是未定义行为的第三个原因。< / p>

在循环之后,使用修改后的指针free调用y,这也会导致未定义的行为。并且你不会释放你在循环中分配的名字,所以也有多个内存泄漏。


根本不需要预先分配节点,只需在需要时进行分配。

这样的东西
ranklist *head = NULL;
FILE *fp = fopen(...);

// Read the file and create the list
char buffer[256];
while (fgets(buffer, sizeof(buffer), fp) != NULL)
{
    ranklist *node = malloc(sizeof(ranklist));
    node->name = malloc(strlen(buffer));  // Will allocate a little more than needed

    sscanf(buffer, "%d %s", &node->point, node->name);

    node->next = head;
    head = node;
}

// Print the list
for (ranklist *n = head; n != NULL; n = n->next)
{
    printf("%d %s\n", n->point, n->name);
}

// Free the list
while (head != NULL)
{
    // Unlink the first node in the list
    ranklist *n = head;
    head = n->next;

    // And free it
    free(n->name);
    free(n);
}

上面的代码没有任何错误检查,在为名称分配空间时也有一些开销,但它是安全的,它不会处理不切实际的长名称,并且列表实际上是一个堆栈(最后读取的项目将在列表中排在第一位。)


使用fgets读取缓冲区中名称长度的函数:

size_t get_name_length(char *buffer)
{
    // Since the buffer was read with `fgets` we need to get rid
    // of the newline at the end, if it's there
    size_t length = strlen(buffer);
    if (buffer[length - 1] == '\n')
        buffer[length - 1] = '\0';  // "Remove" by terminating the string

    // Find the space dividing the point and the name
    char *space = strchr(buffer, ' ');

    // Just in case there are multiple whitespace characters in the string
    while (*space != '\0' && isspace(*space))
        ++space;

    // Now `space` points to the first non-space letter in the name
    // (or to the string terminator, if there's no name

    // Then length of the name is the remainder of the string
    return strlen(space);
}

答案 2 :(得分:0)

FILE *fp = fopen("result.txt","r");
int name_length;
//Just create a link if you use as an array
//int lines = how_many_records(fp);
//ranklist *r = malloc(lines * sizeof(*r));
ranklist *first=NULL, *curr, *r;
int point;

while(1==fscanf(fp, "%d", &point)){
    r = malloc(sizeof(*r));//allocate one record
    r->next = NULL;
    r->point = point;
    name_length = how_many_letter(fp);
    r->name = malloc(name_length + 1);
    fscanf(fp, "%s", r->name);
    //make link
    if(first == NULL)
        first = curr = r;
    else
        curr = curr->next = r;
}
fclose(fp);

for (r = first; r != NULL; r = r->next){
    printf("%d %s\n", r->point, r->name);
}
for (r = first; r != NULL; ){
    ranklist *tmp = r->next;//Save next for free(r)
    free(r->name);
    free(r);
    r = tmp;
}

//output the list
void print(ranklist *first){
    while(first != NULL){
        printf("%d %s\n", first->point, first->name);
        first = first->next;
    }
}