помощь с домашним заданием - PullRequest
1 голос
/ 09 апреля 2011

Для выполнения задания часть того, что я должен сделать, включает использование malloc и realloc.Сначала я создаю двумерный массив символов с размерами, равными количеству строк и количеству символов.Затем я использую malloc, чтобы выделить достаточно памяти для хранения ввода из какого-либо файла.Используя fgets, я читаю по одной строке за раз и сохраняю ее в массиве.Эта часть работает нормально (или я так думаю).Проблема возникает, когда я пытаюсь перераспределить память для большего количества строк, если это необходимо.Программа должна выглядеть следующим образом:

Создать массив символов из 50 строк, по 80 символов в строке (работает)

Используйте fgets для чтения по одной строке за раз исохранить его в массиве (работает)

Когда прочитано 50 строк, перераспределить массив, чтобы учесть 100 строк (не работает)

Продолжать перераспределение по мере необходимости (не работает)

Это то, что я имею до сих пор (по крайней мере, ядро, я опустил нерелевантный код):

#define NUMBER_OF_LINES 50
#define CHARACTERS_PER_LINE 80

FILE *inputFile = fopen("some.text", "r");

char **lines;
lines = malloc(NUMBER_OF_LINES * sizeof(*lines));
int i;
for (i = 0; i < NUMBER_OF_LINES; i++)
  *(lines+i) = malloc(CHARACTERS_PER_LINE * sizeof(char));

int linesRemaining = NUMBER_OF_LINES;
int reallocCount = 1;
i = 0;
while (!feof(inputFile)) {
  if (!linesRemaining) {
    reallocCount++;
    lines = realloc(lines, (NUM_OF_LINES * reallocCount) * sizeof(*lines));
    linesRemaining = NUM_OF_LINES;
  }
  fgets(*(lines+i), CHARS_PER_LINE, inputFile);
  i++;
  linesRemaining--;
}

Моя интуиция говорит мне, что проблема в realloc, поэтому яЯ объясню, что я думаю делает.

realloc(lines, (NUM_OF_LINES * reallocCount) * sizeof(*lines));

Первый аргумент lines - это указатель, который я хотел бы перераспределить определенное количество памяти.NUM_OF_LINES - это сумма, на которую я бы хотел увеличить размер.Я умножаю это на reallocLinesCount, это счетчик, который отслеживает, сколько наборов из 50 линий мне нужно иметь.sizeof(*lines) часть имеет размер указателя на char.

Спасибо за чтение, и любая помощь очень ценится:)

РЕДАКТИРОВАТЬ: спасибо всем за ответы;У меня сейчас нет времени, чтобы прочитать все ответы прямо сейчас, но все ваши ответы будут более внимательно прочитаны и поняты, как только этот неизбежный срок истечет: D

Ответы [ 5 ]

2 голосов
/ 09 апреля 2011

Мой девиз: «скажи, что ты имеешь в виду». В вашем случае вы хотите увеличить свой массив, когда он недостаточно велик для хранения ваших данных.

FILE *in;      // you fill this in
int nlines=50; // initial value
char **buffer=malloc(nlines * sizeof *buffer);
int i=0;

for(int i=0; !feof(in); ++i)
{
  if(i>=nlines)
    buffer=realloc(buffer, (nlines+=50)*sizeof *buffer);

  buffer[i]=malloc(80);
  fgets(buffer[i], 80, in);
}
2 голосов
/ 09 апреля 2011

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

char **oldLines = lines;
lines = realloc(...);

(цель oldLines - сохранить исходный указатель на случай, если realloc() не хватит памяти и вернет NULL, как подсказывает @Brian L.).

1 голос
/ 09 апреля 2011

Давайте сначала посмотрим, как realloc() работает . Возвращает указатель на new память при успехе и NULL при ошибке. При неудаче это не прикоснуться к старой памяти, и в случае успеха free(), после копирования ваши данные на новое место.

Итак, способ безопасного использования realloc():

/* allocate memory using malloc() */
ptr = malloc(N * sizeof *ptr);
/* make sure malloc succeeded */
...
/* call realloc() */
new_ptr = realloc(ptr, M * sizeof *new_ptr);
/* see if it succeeded */
if (new_ptr) {
    /* okay, we can set ptr */
    ptr = new_ptr;
} else {
    /* realloc failed, old pointer still valid */
}

Итак, первое, что вы используете realloc() неправильно. Вы должны никогда сказать x = realloc(x, ...);, потому что если realloc() не удается, вы назначаете x на NULL, и старая память теряется. Это утечка памяти.

Теперь перейдем к вашей проблеме. Допустим, вы успешно прочитали NUMBER_OF_LINES строки. Теперь вы хотите освободить место для дополнительного NUMBER_OF_LINES строки. Вы бы сделали:

char **new_lines = realloc(lines, NUMBER_OF_LINES*reallocCount*sizeof *new_lines);
if (new_lines) {
    lines = new_lines;
} else {
    fprintf(stderr, "realloc failed!\n");
    return;
}

/* Now, lines[NUMBER_OF_LINES] to lines[2*NUMBER_OF_LINES-1] are
 * available to point someplace useful.  They don't point anywhere
 * useful yet.  We have to allocate memory for them, just like earlier */

start = NUMBER_OF_LINES*reallocCount;
for (i=0; i < NUMBER_OF_LINES; ++i) {
    /* You weren't allocating memory here, and were writing to
     * lines[0] through lines[NUMBER_OF_LINES-1], which is not what
     * you want. */
    lines[start+i] = malloc(CHARS_PER_LINE * sizeof *lines[start+i]);
    /* check the result of malloc here */
}
fgets(lines[start+i], CHARS_PER_LINE, inputFile);

Последнее замечание: почти всегда неправильно использовать while (!feof(fp)) читать строки из файла.

1 голос
/ 09 апреля 2011

Вы выделяете больше указателей на строки, но не сами строки. Это в вашем коде в начале:

for (i = 0; i < NUMBER_OF_LINES; i++)
   *(lines+i) = malloc(CHARACTERS_PER_LINE * sizeof(char));

Таким образом, после того, как вы выделили количество строк для каждой строки, вы выделяете место для самой строки. Вы забыли сделать это для новых строк при перераспределении.

1 голос
/ 09 апреля 2011

Вот как вы должны перераспределить:

char **new_lines = realloc(lines, (NUM_OF_LINES * ++reallocLinesCount) * sizeof(*lines));
if (new_lines)
{
    lines = new_lines;
}
else
{
    // Memory allocation fails. Do some error handling.
}

Читать Ссылка на реаллок для деталей.

РЕДАКТИРОВАТЬ

Вам нужно больше выделения для каждой новой строки.

...