从文件读取字符数组,C
我遇到了一些与此代码有关的问题,并且会介意获得一些帮助。此功能从文件读取到动态分配的内存从文件读取字符数组,C
感谢@JonathanLeffler寻求帮助 - 功能缩进功能完美!但是又出现了一个问题:使用函数read_file从文件读取到char数组,稍后传递给缩进。
============================================== ===========================
//--------------- read_file valgrind validations --------------------
==396== 144 bytes in 1 blocks are definitely lost in loss record 62 of 66
==396== at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==396== by 0x401AC1: read_file (polisher.c:24)
==396== by 0x4025CE: test_indent (test_source.c:174)
==396== by 0x406BC7: srunner_run (in /tmc/test/test)
==396== by 0x402C67: tmc_run_tests (tmc-check.c:134)
==396== by 0x402902: main (test_source.c:235)
==396==
================ =====================================
char *read_file(const char *filename)
{
FILE *f = fopen(filename, "r");
if(!f)
return NULL;
int n = 0, c = 0;
char *a = NULL;
c = fgetc(f);
while(c != EOF)
{
n++;
c = fgetc(f);
}
freopen(filename, "r", f);
a = calloc(n + 1, sizeof(char));
c = fgetc(f);
n = 0;
while(c != EOF)
{
a[n] = c;
n++;
c = fgetc(f);
}
a[n] = '\0';
fclose(f);
return a;
}
====== ================================================== ========
START_TEST(test_indent)
{
char *str = read_file("testifile.c");
if (!str) str = read_file("test/testifile.c");
if (!str) {
fail("[M6.01.c] read_file(\"testifile.c\") returned NULL");
}
char *res = indent(str, " ");
if (!res) {
free(str);
free(res);
fail("[M6.01.c] indent(\"testifile.c\") returned NULL");
}
char buf[OUTPUTLEN];
if (mycompare_new(res, ref61c, buf, OUTPUTLEN)) {
free(res);
free(str);
fail("[M6.01.c] Invalid string from indent(\"testifile.c\"): %s", buf);
}
free(str);
free(res);
test_complete();
}
END_TEST
您的基本问题是添加si的代码ngle字符到输出缓冲区不检查是否有空间用于多余的字符,并且可能没有。您可以通过使用更长的缩进(例如" /* Look Ma! */ "
,它是16个字符)来更快地修复错误。
如果您目前有:
continue;
}
dest[dest_offset++] = c;
input++;
}
蛮力和粗心解决方案增加了:
continue;
}
if (dest_offset >= dest_len)
{
printf("XX: DO = %zu, DL = %zu, PL = %zu, LV = %zu\n", dest_offset, dest_len, pad_len, pad_level);
putchar('@');fflush(0);
char *ptr = realloc(dest, dest_len * 2);
if(!ptr)
{
free(dest);
return NULL;
}
dest_len *= 2;
dest = ptr;
}
putchar('.');fflush(0);
dest[dest_offset++] = c;
input++;
}
哦,我留下了一些调试代码,我结束了使用上的显示。我添加了很多相似的打印代码。在循环顶部的断言也有帮助:assert(dest_offset <= dest_len);
。当它开始发射时,情况变得更加清晰(但我花了一段时间才知道它为什么发射)。我还屠杀了测试的换行处理代码:
if (dest_offset >= dest_len || (pad_len * pad_level + 1) >= (dest_len - dest_offset))
{
printf("YY: DO = %zu, DL = %zu, PL = %zu, LV = %zu\n", dest_offset, dest_len, pad_len, pad_level);
putchar('@');fflush(0);
char *ptr = realloc(dest, dest_len * 2);
if(!ptr)
{
free(dest);
return NULL;
}
dest_len *= 2;
dest = ptr;
}
但realloc()
从来没有发射,这是惊喜之一。
我认为你需要一个函数来添加一个字符到你的输出缓冲区,并且你需要将输出缓冲区控制包装到一个结构体中(struct Buffer { char *buffer; size_t maxlen; size_t curlen; }
或其附近),并且你有一个函数处理(重新)分配需要的空间。这将避免“蛮力和粗心”解决方案的明显重复。如果你愿意,你可以使它成为一个static inline
函数 - 编译器可以避免一些开销,而不会影响代码的可读性。这两个循环还有一个令人讨厌的重复,即将多个缩进添加到缓冲区中。当然,最好用另一个函数来处理 - 但它会与'加一个字符'不同,因为你可以明智地检查足够的空间并重新分配一次。或者编写函数来获取长度和指向非空终止的缓冲区的指针(因此单个字符的长度为1,填充字符串的长度为pad_len
),并且单个函数可以完成大量工作 - 可能是更好的解决方案。我仍然将控件打包到一个结构中,并让编译器进行优化。
测试main()
:
int main(void)
{
char data[] = "#include <stdio.h>\nint main(void)\n{\nputs(\"Hello World!\\n\");\nreturn 0;\n}\n";
printf("Before: [[%s]]\n", data);
fflush(0);
char *reformatted = indent(data, " /* Look Ma! */ ");
printf("Indent: -complete-\n");
fflush(0);
printf("Source: [[%s]]\n", data);
fflush(0);
printf("Target: [[%s]]\n", reformatted);
free(reformatted);
return 0;
}
非常感谢你,我已经编辑了我的代码和问题,但现在有一个小问题... intend函数完美工作,服务器说我已经通过了这个练习,但现在它抱怨read_file,但一切看起来都很完美...... – JasonUrban
的就是你得到的第一个问题的错误?对于valgrind输出,你能指出哪一行出现错误(哪一行代码是行116,127,...)? – Garf365
@ Garf365'strncpy(dest + dest_offset,pad,pad_len + 1);'是116.'dest [dest_offset ++] = c; '127。当我尝试发送这个函数到服务器时,它说“提前返回值1”。第一个问题的错误信息是“接收信号:SIGABRT(中止)。对于主,PID 9424” – JasonUrban
请编辑您的问题以添加此信息。此外,检查每次函数'indent'被提及到valgrind输出中,并添加关于每行的信息 – Garf365