以下函数必须将一条线分成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;
}
Run Code Online (Sandbox Code Playgroud)
您正在使用未定义的常量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')
{
...
}
Run Code Online (Sandbox Code Playgroud)
实际上,你在循环中读取了一个字符并且没有正确检查它.然后,您可以使用ungetc()将字符首先读回到输入流中; 它使输入处理更加均匀.或者,如果第一次调用fgetc()是在循环控件中并返回EOF ,则可以进行设置以使一切正常.
正如汤米指出的那样,你必须捕捉到的输出realloc(); 无法保证它会返回其输入指针作为结果.您现在还应该了解到,您没有将结果保存realloc()到指定为其第一个参数的变量中.如果你这样做,你会立即泄漏内存并且重新分配失败(因为你丢失了指向旧内存的指针 - 它只是归零).所以,为了安全起见,你使用:
char **new_array = realloc(l, (lcounter+1) * sizeof(*new_array));
if (new_array == 0)
...handle out of memory...
else
l = new_array;
Run Code Online (Sandbox Code Playgroud)
这里有几点.你分配了(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(在链接部分的底部).