以下函数必须将一条线分成2行或更多行,每行都比s短。
char **splitline(FILE *fp, int s)
{
char **l;
char c;
int ccounter;
int lcounter;
c = fgetc(fp);
if (c == EOF)
{
return NULL;
}
lcounter=0;
l = malloc(sizeof(char **));
l[lcounter] = malloc((SIZE+2)*sizeof(char));
ccounter = 0;
while (c != EOF && c != '\n')
{
l[lcounter][ccounter] = c;
ccounter++;
c = fgetc(fp);
if (ccounter == SIZE)
{
l[lcounter][ccounter] = '\n';
ccounter++;
l[lcounter][ccounter] = '\0';
realloc(l, (lcounter+2) * sizeof(char **));
lcounter++;
l[lcounter] = malloc((SIZE+2) * sizeof(char));
ccounter = 0;
}
}
if (ccounter == 0)
{
l[lcounter][ccounter] = '\0';
}
else
{
l[lcounter][ccounter] = '\n';
ccounter++;
l[lcounter][ccounter] = '\0';
realloc(l, (lcounter+2) * sizeof(char **));
lcounter++;
ccounter = 0;
l[lcounter] = malloc((SIZE+2) * sizeof(char));
l[lcounter][ccounter] = '\0';
}
return l;
}
答案 0 :(得分:5)
您正在使用未定义的常量SIZE而不是参数s
来控制行的最大长度。由于s
是一个有符号整数,你应该检查它是否合理(它应该是正数(非零)数字,可能不大于1 MiB;也许你想设置一个比1更大的下限;也许你如果呼叫者搞砸了,则默认为80,或者您可能会返回错误)。
您正在使用char c;
保存使用fgetc()
读取的值;遗憾的是,这意味着您的EOF测试不可靠。当有人提供'ÿ'(y-umlaut,ISO 8859-1中的十六进制0xFF,ISO 8646中的U + 00FF - Unicode)或者根本不会停止时,你要么提前停止类型char
是签名还是未签名。永远记住:getchar()
和亲戚返回int
!
变量l
正在引发与常量1
的混淆;一般都要避免它。
如果直接测试fgetc()
的结果,主循环条件会更好。
int c;
while ((c = fgetc(fp)) != EOF && c != '\n')
{
...
}
实际上,你在循环中读取了一个字符并且没有正确检查它。然后,您可以使用ungetc()
将字符首先读回输入流;它使输入处理更加均匀。或者,如果第一次调用fgetc()
在循环控件中并且它返回EOF,您可以进行设置以便一切正常。
正如Tommy所指出,您必须捕获realloc()
的输出;无法保证它会返回其输入指针作为结果。您现在还应该了解到,不将realloc()
的结果保存到指定为其第一个参数的变量中。如果你这样做,你会立即泄漏内存并且重新分配失败(因为你丢失了指向旧内存的指针 - 它只是归零)。所以,为了安全起见,请使用:
char **new_array = realloc(l, (lcounter+1) * sizeof(*new_array));
if (new_array == 0)
...handle out of memory...
else
l = new_array;
这里有几点。您分配了(lcounter+2)
个值,但我认为您只使用其中一个(除非有一个终端空指针标记数组的结尾)。您指定了sizeof(char **)
,但实际上您需要一组char *
值。幸运的是,所有(对象)指针的大小都相同--C标准保证;只有POSIX保证函数指针与对象指针的大小相同(C标准没有)。所以,sizeof(char **) == sizeof(char *)
你是安全的,但你不是在问你想要什么。
有关realloc()
可能失败的讨论的必然结果malloc()
也可能失败。您应该错误检查内存分配 - 或者使用标准库的一组封面函数,只有在返回的指针不为空时才返回。如果你不检查它,你的程序最终会因内存分配失败而崩溃 - 即使在具有24 GiB主内存的机器上(尽管可能需要一段时间才能达到这一点)。
代码中有很多重复。你应该避免这样做。这意味着可能使用子功能来管理内存分配。
如果你解决这些问题,那么你就有机会获得正常工作。您还应编写代码以释放您返回的已分配内存,以便用户无需为您设计方法。总是担心谁会释放分配的内存以及它将如何发布。
Chris Lutz问道:
标准在哪里保证所有对象指针类型的大小都相同?
我认为(C99-ISO / IEC 9899:1999)标准的相关部分是:
§6.3.2.3指针
1指向void的指针可以转换为指向任何不完整或对象的指针 类型。指向任何不完整或对象类型的指针可以转换为指向void的指针 又回来了;结果应该等于原始指针。
这基本上说所有对象指针类型都可以转换为void指针并再次返回而不会丢失信息,这意味着它们必须都是相同的大小。请注意,“对象指针”类别不包含“函数指针”。
POSIX标准的相关部分(关于函数指针)是§2.12.3(在链接部分的底部)。
答案 1 :(得分:4)
我能发现的主要内容:realloc可能无法将缓冲区保留在同一地址。你应该使用
l = realloc(...)
实际上,请参阅下面Matteo的评论。 Realloc可以做以下三件事之一:
在最后一种情况下,不检查返回值的赋值会导致内存泄漏。