了解内存分配的C代码示例

时间:2011-11-27 21:56:39

标签: c memory pointers io

我是C的新手,我正在阅读K& R的“The C Programming Language”来学习它。我对第2版第109页上出现的这个示例函数有疑问:

/* readlines:  read input lines */
int readlines(char *lineptr[], int maxlines)
{
   int len, nlines;
   char *p, line[MAXLEN];
   nlines = 0;
   while ((len = getline(line, MAXLEN)) > 0)
       if (nlines >= maxlines || p = alloc(len) == NULL)
           return -1;
       else {
           line[len-1] = '\0';  /* delete newline */
           strcpy(p, line);
           lineptr[nlines++] = p;
       }
   return nlines;
}

我想知道为什么*p在这里是必要的? p被分配内存,然后line被复制到其中。为什么不能只使用line,所以最后lineptr[nlines++] = p可以替换为lineptr[nlines++] = line

6 个答案:

答案 0 :(得分:1)

如果你没有为每一行分配内存,你最终将lineptr作为一个数组,其中包含指向你读取的最后一行的指针(更不用说堆栈内存可能是覆盖)。在读取时为每一行分配内存会使返回的数组有意义。举个例子,假设line恰好在地址0x1000的堆栈上分配。如果您进行了建议的更改,则生成的8行文件的lineptr数组将为:

0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000

Yowch!在读取每行时为每行分配内存,然后将行复制到分配的内存中是唯一的解决方案。

答案 1 :(得分:1)

lineptr[nlines++] = line;

会向lineptr填充指向该函数本地内存的指针,并且该函数返回后该内存将变为无效。 lineptr数组的所有元素的值都相同且等于line

所以这里需要分配。您确实需要将line的内容复制到新分配的内存位置,该位置在函数返回后仍然存在。

答案 2 :(得分:1)

你需要为每一行分配存储。你不能像你建议的那样捕获line的值,因为那是一个本地变量函数返回后的范围(在这个特定的例子中,它在每次迭代时被覆盖)。

你可以通过line直接对getline的元素(你将随时分配)来避免lineptr,但是你无法摆脱p

答案 3 :(得分:1)

需要为每一行分配一大块新内存。指针p是我们对该内存的唯一句柄。我们指定lineptr[nlines++] = p,以便我们可以引用每个内存块(例如行)作为数组lineptr的一部分。

答案 4 :(得分:1)

c / c ++中lineptr[nlines++] = p种类的分配,将lineptr[nlines++]的地址设置为p所指向的地址,此处不会复制数据。

因此,line的地址始终是相同的地址;所以lineptr[nlines++] = line意味着所有lineptr[i]都指向同一个地址。 最糟糕的是,在函数返回后,line不再存在,因此每个lineptr[i]都指向一个无效的地址。

使用p为每一行分配新内存,并确保该内存的地址在函数之间仍然有效(直到你释放它为止)。

答案 5 :(得分:0)

好的,让我们告诉你如何在没有char *p的情况下做同样的事情......我将略微修改代码。

/* readlines:  read input lines */

#include <string.h>

/* put that include line below #include <stdio.h> if you don't already have this
   string.h defines strdup() function which we use below */


int readlines(char *lineptr[], int maxlines)
{
   int len, nlines;
   char line[MAXLEN];
   nlines = 0;

   while ((len = getline(line, MAXLEN)) > 0) {
           line[len-1] = '\0';  /* delete newline */
           lineptr[nlines] = strdup(line); /* allocate memory and make a copy */
           if (lineptr[nlines] == NULL) {
                  return -1;
           }

           nlines++;

           if (nlines >= marlines) 
               break;


   }

   return nlines;
}

此代码最接近,不使用临时char *p

事实是,虽然这在功能上是正确的,但使用临时变量char *p来测试所有分配和检索使代码更清晰,易于遵循教学目的。它还明确地将字符串内存的分配显示为单独的步骤,隐藏在strdup