有关Malloc和链接列表的问题

时间:2016-10-12 05:00:24

标签: c linked-list malloc

我有一个函数可以读取每行填充一个单词的文本文件。以下是我使用

的文本文件示例
and
but
five
follows
four
has
is
like
line
lines
littlest
not
once
one
only
other
six
the
three
twice
two
word
words

代码:

typedef struct node node_t;

struct node {
    char data[MAX_WORD];
    int term;
    node_t *next;
};

node_t *head; 

int
int_struct(int lines){
    FILE *fp;
    char ch;
    int n = 0, i, switch_num=1, test_first=0, test_first_2=0;
    node_t *node, *curr_add; 
    fp = fopen("text.txt", "r");
    node = (node_t*)malloc(sizeof(node_t));
    for (i=1; i<=lines; i++){
        switch_num = 1;
        n=0;
        if (test_first != 0){
            if (test_first_2){
                node = (node_t*)malloc(1000000);
            }
            test_first_2=1;
            while ((ch = getc(fp)) != '\n'){
                node -> term = i;
                node -> data[n] = ch;
                n++;
            }
            curr_add -> next = node;
            curr_add = node;
        }
        else{
            test_first = 1;
            head = curr_add = node;
        }
    }
    curr_add -> next = NULL;
    fclose(fp);
    return num;
}

我想要做的是阅读每个单词并将其添加到链接列表中 但是我遇到了malloc的麻烦(目前我只是添加了很多字节)并且需要建议如何在我的函数中正确使用它。我已经进行了一般搜索,并尽力尝试做大多数示例所做的事情。但我似乎仍然无法使我的功能正常工作。例如,每次执行程序时,它都会读取并将所有单词添加到链表中。但是,程序在最后一个单词崩溃,并返回NULL。如果有人能指出我正确的方向,我将非常感激。

1 个答案:

答案 0 :(得分:0)

问题

  1. 没有检查返回值。特别是fopenmalloc 可能会返回NULL。如果他们这样做,你会发现分段错误错误 首先尝试访问返回的值。

  2. 过于复杂的逻辑。您不需要这些switch_numtest_firsttest_first_2 变量(见下面的示例代码)。

  3. 当您逐行阅读文本文件时,无需getc - 使用 而是fgets

  4. 内存分配太多。每行不需要超过sizeof(node_t) + 字节的长度。

  5. 未释放分配的内存。动态内存应该被释放为 很快就不需要了。

  6. 使用链表

    的示例

    以下内容将文本文件读入链接列表。内存分配给 每个列表项,以及文件中每行产生n * 2内存的行 分配,其中n是文件中的行数。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> /* strerror, strdup */
    #include <errno.h>
    
    typedef struct _node {
      unsigned line;
      char *data;
      struct _node *next;
    } node_t;
    
    
    static void
    destroy_list(node_t *list)
    {
      node_t *node;
    
      for (node = list; node; node = node->next) {
        if (node->data != NULL)
          free(node->data);
        free(node);
      }
    }
    
    
    static node_t *
    create_list_item(const char *data, unsigned line)
    {
      node_t *node = calloc(1, sizeof(node_t));
    
      if (node == NULL) {
        fprintf(stderr, "calloc: %s\n", strerror(errno));
      } else {
        node->line = line;
        node->data = strdup(data);
        if (node->data == NULL) {
          fprintf(stderr, "strdup: %s\n", strerror(errno));
          free(node);
          node = NULL;
        }
      }
    
      return node;
    }
    
    
    /* Returns pointer to new linked list */
    static node_t *
    read_file(FILE *fp, char *buf, size_t buf_len)
    {
      node_t *list = NULL;
      node_t *prev = NULL;
      node_t *node;
      unsigned i;
    
      for (i = 0; fgets(buf, buf_len, fp); prev = node) {
        if ((node = create_list_item(buf, ++i)) == NULL) {
          fprintf(stderr, "calloc: %s\n", strerror(errno));
          break;
        }
    
        if (list == NULL)
          list = node;
    
        if (prev != NULL)
          prev->next = node;
      }
    
      return list;
    }
    
    
    static void
    print_list(const node_t *list)
    {
      const node_t *node;
    
      for (node = list; node; node = node->next)
        printf("%d: %s", node->line, node->data);
    }
    
    
    int main(int argc, char const* argv[])
    {
      const char *filename = "text.txt";
      char buf[1024] = {0};
      FILE *fp = NULL;
      node_t *list = NULL;
    
      if (NULL == (fp = fopen(filename, "r"))) {
        fprintf(stderr, "failed to open file %s: %s\n",
            filename, strerror(errno));
        return 1;
      }
    
      list = read_file(fp, buf, sizeof(buf));
      fclose(fp);
    
      if (list) {
        print_list(list);
        destroy_list(list);
      }
    
      return 0;
    }
    

    使用动态数组的示例

    为文件中的每一行(两次)分配内存效率很低, 不仅因为系统调用(mallocrealloc等)代价高昂, 但也因为物品是非连续放置的。访问连续 记忆区域通常更快。

    在以下代码中,链接列表将替换为动态数组。我们 一次初始化10行内存。根据需要增加尺寸。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> /* strerror, strdup */
    #include <errno.h>
    
    typedef struct _node {
      size_t line;
      char *data;
    } node_t;
    
    
    static void
    destroy_array(node_t *array, size_t size)
    {
      size_t i;
      node_t *item;
    
      for (i = 0; i < size; i++) {
        item = &array[i];
        if (item->data)
          free(item->data);
      }
      free(array);
    }
    
    
    static void
    print_array(node_t *array, size_t size)
    {
      size_t i;
      node_t *item;
    
      for (i = 0; i < size; i++) {
        item = &array[i];
        if (item->data) {
          printf("%ld: %s", item->line, item->data);
        }
      }
    }
    
    static node_t *
    read_file(FILE *fp, char *buf, size_t buf_len,
        const size_t array_step, size_t *array_size)
    {
      node_t *item;
      node_t *array = calloc(array_step, sizeof(node_t));
      size_t size = 0;
      if (array == NULL) {
        fprintf(stderr, "calloc:%s\n", strerror(errno));
        return array;
      }
    
      while (fgets(buf, buf_len, fp)) {
        if (size && size % array_step == 0) {
          array = realloc(array, sizeof(node_t) * (array_step + size));
          if (array == NULL) {
            fprintf(stderr, "realloc:%s\n", strerror(errno));
            break;
          }
        }
        item = &array[size++];
    
        item->line = size;
        item->data = strdup(buf);
        if (item->data == NULL) {
          fprintf(stderr, "strdup: %s\n", strerror(errno));
          break;
        }
      }
    
      *array_size = size;
    
      return array;
    }
    
    int main(int argc, char const* argv[])
    {
      node_t *array;
      const size_t array_step = 10;
      size_t array_size;
      const char *filename = "text.txt";
      char buf[1024] = {0};
      FILE *fp = NULL;
    
      if (NULL == (fp = fopen(filename, "r"))) {
        fprintf(stderr, "failed to open file %s: %s\n",
            filename, strerror(errno));
        return 1;
      }
    
      array = read_file(fp, buf, sizeof(buf), array_step, &array_size);
      fclose(fp);
    
      if (array) {
        print_array(array, array_size);
        destroy_array(array, array_size);
      }
    
      return 0;
    }
    

    请注意node_t结构中的更改。