Arhn - архитектура программирования

Проблемы с 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. Если кто-то может указать мне в правильном направлении, я был бы очень благодарен.

12.10.2016

  • Нужно ли нам использовать наши хрустальные шары, чтобы увидеть определение struct node_t? Кроме того, почему вы выделяете 1 миллион байт для каждого узла? Вам нужно только sizeof(struct node_t). Выделение данных для word — это отдельная история. И так обратитесь к моему первому вопросу. 12.10.2016
  • Вы используете глобальные переменные в этой функции, которые вы не определили для нас. Вам нужно вставить полный пример вашей проблемы. И минимальную тоже: есть ли у вас проблемы с malloc даже при чтении не из файла? 12.10.2016
  • Что касается вашего сбоя, вполне вероятно, что когда getc возвращает EOF, вы постоянно зацикливаетесь и добавляете байты к своему слову (потому что EOF != '\n'), тогда как на самом деле вы должны выйти из цикла. Если это так, вы должны были бы найти его немедленно, если бы использовали отладчик. 12.10.2016
  • почему бы вам не подумать об использовании fgets и облегчить жизнь 12.10.2016
  • Извините, первый пост. Я только что обновил определение структуры. Единственная причина, по которой я не помещаю всю программу, заключается в том, что она большая и делает некоторые другие вещи, которые работают нормально. Но если вам это действительно нужно, я могу обновить пост со всей функцией. Благодарность! 12.10.2016
  • Возвращаясь к тому, что ты говоришь, Пэдди. Нужно ли мне иметь realloc каждый раз, когда я добавляю ch в массив данных? 12.10.2016

Ответы:


1

вопросы

  1. нет проверок возвращаемых значений. В частности, fopen и malloc могут возвращать NULL. Если они это сделают, вы поймаете ошибку ошибки сегментации при первой попытке доступа к возвращаемому значению.

  2. Слишком сложная логика. Вам не нужны эти переменные switch_num, test_first и test_first_2 (см. пример кода ниже).

  3. Нет необходимости в getc, когда вы читаете текстовый файл построчно — вместо этого используйте fgets.

  4. Слишком много выделенной памяти. Вам не нужно больше, чем sizeof(node_t) + длина строки байт на строку.

  5. Выделенная память не освобождена. Динамическая память должна быть освобождена, как только она станет не нужна.

Пример использования связанного списка

Следующее читает текстовый файл в связанный список. Память выделяется для каждого элемента списка и для каждой строки в файле, в результате чего выделяется 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;
}

Пример использования динамического массива

Неэффективно выделять память для каждой строки (дважды) в файле не только потому, что системные вызовы (malloc, realloc и т. д.) являются дорогостоящими, но и потому, что элементы размещаются несмежными. Доступ к смежной области памяти обычно выполняется быстрее.

В следующем коде связанный список заменяется динамическим массивом. Инициализируем память сразу на 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.

12.10.2016
Новые материалы

Коллекции публикаций по глубокому обучению
Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

Представляем: Pepita
Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

Советы по коду Laravel #2
1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

3 способа решить квадратное уравнение (3-й мой любимый) -
1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

Создание VR-миров с A-Frame
Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

Демистификация рекурсии
КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..