您触及了困扰所有新 C 程序员的问题之一。如何动态分配所需的所有内存以摆脱静态限制,同时仍然跟踪内存中的“内容”集合。当您需要从输入中读取未知数量的“事物”时,通常会出现此问题。初始选项是(1)声明一些足够大的限制(违背目的),或者(2)根据需要动态分配指针。
显然,目标是(2)。然而,你随后遇到了问题“我如何跟踪我分配的内容?”这本身就是困扰初学者的一个问题。问题是,如果我使用一堆指针动态分配,**如何迭代列表以获取我的“东西”?另外,您必须初始化一些初始数量的指针(除非使用链表等高级数据结构),所以下一个问题是“我用完了怎么办?”
通常的解决方案是分配一组初始指针,然后当达到限制时,重新分配到原始指针的两倍,然后继续。 (正如格雷森在回答中指出的那样)。
然而,还有一个技巧可以迭代列表以获取您的“东西”这是值得理解的。是的,您可以分配malloc
并跟踪所使用的指针数量,但您可以将自己从绑定中解放出来counter通过最初分配到您的指针列表calloc
。这不仅分配空间,而且还将分配的指针设置为NULL
(或 0)。这允许您使用简单的方法迭代列表while (pointer != NULL)
。这提供了很多好处当涉及到将指针集合传递给函数等时。缺点(最小的缺点)是您需要编写一个使用的重新分配方案calloc
在需要时分配新空间。 (真糟糕,我变得更聪明了——但我必须努力做到这一点......)
您可以评估是否使用malloc/realloc
现成的,或者是否使用重新分配calloc
and a custom reallocate function
取决于您的要求。无论如何,了解两者只会为您的编程工具箱添加更多工具。
好吧,闲聊够了,这些废话的例子在哪里?
以下两个示例都只是从任何文本文件中读取所有行并将这些行(带有指针索引号)打印回标准输出。两者都期望您提供要读取的文件名作为命令行上的第一个参数。两者之间唯一的区别是第二个有重新分配calloc
完成是一个custom reallocation function
。他们都分配255
最初的指针数量,每次达到限制时将指针数量加倍。 (为了好玩,你可以设置MAXLINES
像一些小东西10
并强制重复重新分配进行测试)。
第一个在 main() 中重新分配的示例
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
#define MAXLINES 255
void free_buffer (char **buffer)
{
register int i = 0;
while (buffer[i])
{
free (buffer[i]);
i++;
}
free (buffer);
}
int main (int argc, char **argv) {
if (argc < 2) {
fprintf (stderr, "Error: insufficient input. Usage: %s input_file\n", argv[0]);
return 1;
}
char *line = NULL; /* forces getline to allocate space for buf */
ssize_t read = 0; /* number of characters read by getline */
size_t n = 0; /* limit number of chars to 'n', 0 no limit */
char **filebuf = NULL;
char **rtmp = NULL;
int linecnt = 0;
size_t limit = MAXLINES;
size_t newlim = 0;
FILE *ifp = fopen(argv[1],"r");
if (!ifp)
{
fprintf(stderr, "\nerror: failed to open file: '%s'\n\n", argv[1]);
return 1;
}
filebuf = calloc (MAXLINES, sizeof (*filebuf)); /* allocate MAXLINES pointers */
while ((read = getline (&line, &n, ifp)) != -1) /* read each line in file with getline */
{
if (line[read - 1] == 0xa) { line[read - 1] = 0; read--; } /* strip newline */
if (linecnt >= (limit - 1)) /* test if linecnt at limit, reallocate */
{
newlim = limit * 2; /* set new number of pointers to 2X old */
if ((rtmp = calloc (newlim, sizeof (*filebuf)))) /* calloc to set to NULL */
{
/* copy original filebuf to newly allocated rtmp */
if (memcpy (rtmp, filebuf, linecnt * sizeof (*filebuf)) == rtmp)
{
free (filebuf); /* free original filebuf */
filebuf = rtmp; /* set filebuf equal to new rtmp */
}
else
{
fprintf (stderr, "error: memcpy failed, exiting\n");
return 1;
}
}
else
{
fprintf (stderr, "error: rtmp allocation failed, exiting\n");
return 1;
}
limit = newlim; /* update limit to new limit */
}
filebuf[linecnt] = strdup (line); /* copy line (strdup allocates) */
linecnt++; /* increment linecnt */
}
fclose(ifp);
if (line) free (line); /* free memory allocated to line */
linecnt = 0; /* reset linecnt to iterate filebuf */
printf ("\nLines read in filebuf buffer:\n\n"); /* output all lines read */
while (filebuf[linecnt])
{
printf (" line[%d]: %s\n", linecnt, filebuf[linecnt]);
linecnt++;
}
printf ("\n");
free_buffer (filebuf); /* free memory allocated to filebuf */
return 0;
}
在自定义函数中重新分配的第二个示例
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
#define MAXLINES 255
/* function to free allocated memory */
void free_buffer (char **buffer)
{
register int i = 0;
while (buffer[i])
{
free (buffer[i]);
i++;
}
free (buffer);
}
/* custom realloc using calloc/memcpy */
char **recalloc (size_t *lim, char **buf)
{
int newlim = *lim * 2;
char **tmp = NULL;
if ((tmp = calloc (newlim, sizeof (*buf))))
{
if (memcpy (tmp, buf, *lim * sizeof (*buf)) == tmp)
{
free (buf);
buf = tmp;
}
else
{
fprintf (stderr, "%s(): error, memcpy failed, exiting\n", __func__);
return NULL;
}
}
else
{
fprintf (stderr, "%s(): error, tmp allocation failed, exiting\n", __func__);
return NULL;
}
*lim = newlim;
return tmp;
}
int main (int argc, char **argv) {
if (argc < 2) {
fprintf (stderr, "Error: insufficient input. Usage: %s input_file\n", argv[0]);
return 1;
}
char *line = NULL; /* forces getline to allocate space for buf */
ssize_t read = 0; /* number of characters read by getline */
size_t n = 0; /* limit number of chars to 'n', 0 no limit */
char **filebuf = NULL;
int linecnt = 0;
size_t limit = MAXLINES;
FILE *ifp = fopen(argv[1],"r");
if (!ifp)
{
fprintf(stderr, "\nerror: failed to open file: '%s'\n\n", argv[1]);
return 1;
}
filebuf = calloc (MAXLINES, sizeof (*filebuf)); /* allocate MAXLINES pointers */
while ((read = getline (&line, &n, ifp)) != -1) /* read each line in file with getline */
{
if (line[read - 1] == 0xa) { line[read - 1] = 0; read--; } /* strip newline */
if (linecnt >= (limit - 1)) /* test if linecnt at limit, reallocate */
{
filebuf = recalloc (&limit, filebuf); /* reallocate filebuf to 2X size */
if (!filebuf)
{
fprintf (stderr, "error: recalloc failed, exiting.\n");
return 1;
}
}
filebuf[linecnt] = strdup (line); /* copy line (strdup allocates) */
linecnt++; /* increment linecnt */
}
fclose(ifp);
if (line) free (line); /* free memory allocated to line */
linecnt = 0; /* reset linecnt to iterate filebuf */
printf ("\nLines read in filebuf buffer:\n\n"); /* output all lines read */
while (filebuf[linecnt])
{
printf (" line[%d]: %s\n", linecnt, filebuf[linecnt]);
linecnt++;
}
printf ("\n");
free_buffer (filebuf); /* free memory allocated to filebuf */
return 0;
}
看一下这两个例子。知道有很多很多方法来做到这一点。这些示例仅提供了一种方法,该方法提供了使用一些通常无法找到的额外技巧的示例。尝试一下。如果您需要更多帮助,请发表评论。