1

对于作业,我必须做的部分事情涉及使用mallocand 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)部分是指向 a 的指针的大小char

感谢您的阅读,非常感谢您的帮助:)

编辑:谢谢大家的回复;我现在没有时间阅读所有答案,但是一旦这个迫在眉睫的截止日期过去,您的所有答案都会得到更彻底的阅读和理解:D

4

5 回答 5

2

realloc()经常会发现没有足够的可用空间来就地扩展现有阵列;在这种情况下,它将创建一个指定大小的全新数组,将旧数组的内容复制到新数组,释放旧数组,并返回指向新数组的指针。所以你应该写

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

(根据@Brian L 的提示,目的oldLines是保留原始指针以防realloc()内存不足并返回)。NULL

于 2011-04-09T02:52:47.947 回答
2

我的座右铭是:“说出你的意思”。在您的情况下,您的意思是在阵列不足以容纳您的数据时扩大阵列。

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);
}
于 2011-04-09T02:55:32.120 回答
1

这就是你应该重新分配的方式:

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.
}

有关详细信息,请阅读realloc 参考

编辑

您需要为每条新线路分配更多。

于 2011-04-09T02:54:50.277 回答
1

您正在分配更多指向行的指针,而不是行本身。它在您的代码开头:

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

因此,在为每行分配行数后,您为行本身分配空间。当您重新分配时,您忘记为新行执行此操作。

于 2011-04-09T03:09:41.497 回答
1

让我们先看看它是如何realloc()工作的。 它在成功和失败时返回一个指向新内存的指针。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() 失败,你分配xNULL,旧的记忆就会丢失。这是内存泄漏。

现在,谈谈你的问题。假设您已成功读取 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))

于 2011-04-09T03:15:18.940 回答