我写了一个简单的程序,它会打开一个csv文件,读取它,制作一个新的csv文件,并且只写一些列(我不想要所有的列,我希望删除一些会使文件成为更易于管理)。该文件为1.15GB,但fopen()
没有问题。在第一次进展printf()
之后不久,我的while循环中发生了分段错误。
我只测试了csv的前几行,下面的逻辑做了我想要的。 index == 0
的最后一列是(xxx, yyy)\n
形式的奇怪部分(逗号分隔值文件中的,
是荒谬的。)
这是代码,while循环是问题:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
long size;
FILE* inF = fopen("allCrimes.csv", "rb");
if (!inF) {
puts("fopen() error");
return 0;
}
fseek(inF, 0, SEEK_END);
size = ftell(inF);
rewind(inF);
printf("In file size = %ld bytes.\n", size);
char* buf = malloc((size+1)*sizeof(char));
if (fread(buf, 1, size, inF) != size) {
puts("fread() error");
return 0;
}
fclose(inF);
buf[size] = '\0';
FILE *outF = fopen("lessColumns.csv", "w");
if (!outF) {
puts("fopen() error");
return 0;
}
int index = 0;
char* currComma = strchr(buf, ',');
fwrite(buf, 1, (int)(currComma-buf), outF);
int progress = 0;
while (currComma != NULL) {
index++;
index = (index%14 == 0) ? 0 : index;
progress++;
if (progress%1000 == 0) printf("%d\n", progress/1000);
int start = (int)(currComma-buf);
currComma = strchr(currComma+1, ',');
if (!currComma) break;
if ((index >= 3 && index <= 10) || index == 13) continue;
int end = (int)(currComma-buf);
int endMinusStart = end-start;
char* newEntry = malloc((endMinusStart+1)*sizeof(char));
strncpy(newEntry, buf+start, endMinusStart);
newEntry[end+1] = '\0';
if (index == 0) {
char* findNewLine = strchr(newEntry, '\n');
int newLinePos = (int)(findNewLine-newEntry);
char* modifiedNewEntry = malloc((strlen(newEntry)-newLinePos+1)*sizeof(char));
strcpy(modifiedNewEntry, newEntry+newLinePos);
fwrite(modifiedNewEntry, 1, strlen(modifiedNewEntry), outF);
}
else fwrite(newEntry, 1, end-start, outF);
}
fclose(outF);
return 0;
}
编辑:原来问题是csv文件在我没想到的地方,
导致逻辑失败。我最终编写了一个新的解析器,删除了逗号数量不正确的行。它删除了243,875行(约占文件的4%)。我会发布该代码,因为它至少反映了有关free()
的一些评论:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
long size;
FILE* inF = fopen("allCrimes.csv", "rb");
if (!inF) {
puts("fopen() error");
return 0;
}
fseek(inF, 0, SEEK_END);
size = ftell(inF);
rewind(inF);
printf("In file size = %ld bytes.\n", size);
char* buf = malloc((size+1)*sizeof(char));
if (fread(buf, 1, size, inF) != size) {
puts("fread() error");
return 0;
}
fclose(inF);
buf[size] = '\0';
FILE *outF = fopen("uniformCommaCount.csv", "w");
if (!outF) {
puts("fopen() error");
return 0;
}
int numOmitted = 0;
int start = 0;
while (1) {
char* currNewLine = strchr(buf+start, '\n');
if (!currNewLine) {
puts("Done");
break;
}
int end = (int)(currNewLine-buf);
char* entry = malloc((end-start+2)*sizeof(char));
strncpy(entry, buf+start, end-start+1);
entry[end-start+1] = '\0';
int commaCount = 0;
char* commaPointer = entry;
for (; *commaPointer; commaPointer++) if (*commaPointer == ',') commaCount++;
if (commaCount == 14) fwrite(entry, 1, end-start+1, outF);
else numOmitted++;
free(entry);
start = end+1;
}
fclose(outF);
printf("Omitted %d lines\n", numOmitted);
return 0;
}
答案 0 :(得分:1)
你是malloc'ing但从不自由。可能你用尽了memomry,你的一个mallocs返回NULL
,然后调用str(n)cpy
段错误。
在相应的free(newEntry);
来电之后立即添加free(modifiedNewEntry);
,fwrite
可以解决您的内存不足问题。
另请注意,在循环内部,您可以计算包含整个文件的缓冲区buf
的偏移量。这些偏移量保存在int
类型的变量中,其系统的最大值可能对于您正在处理的数字而言太小。另请注意,添加大int
s可能会导致负值,这是segfault的另一个可能原因(负向偏移到buf会将您带到缓冲区外的某些地址,甚至可能无法读取)。
答案 1 :(得分:1)
malloc(3)功能可以(有时确实)失败。
至少代码类似
char* buf = malloc(size+1);
if (!buf) {
fprintf(stderr, "failed to malloc %d bytes - %s\n",
size+1, strerror(errno));
exit (EXIT_FAILURE);
}
我强烈建议您使用memset(buf, 0, size+1)
清除malloc
(或以其他方式使用calloc
....)的成功结果,这不仅仅是因为以下fread
可能会失败(您正在测试)但是为了简化调试和再现性。
同样对于malloc
或calloc
的所有其他来电(你应该总是测试它们以防止失败)....
请注意,按照定义 sizeof(char)
总是 1.因此我删除了它。
正如其他人指出的那样,您有一个memory leak,因为您没有恰当地致电free
。像valgrind这样的工具可以提供帮助。
您需要了解如何使用调试器(例如gdb
)。不要忘记编译所有警告和调试信息(例如gcc -Wall -g
)。并且在没有警告的情况下改进您的代码。
了解如何使用调试器是编程时必不可少的技能(特别是在C或C ++中)。调试技巧(以及使用调试器的能力)在您贡献的每个C或C ++程序中都很有用。
顺便说一句,你可以逐行读取你的文件getline(3)(也可能会失败,你应该测试一下)。