我当前正在尝试创建一个程序,该程序打印通过命令行传入的另一个文本程序的最后10行。函数read()应该从文本文件中读取一行,然后返回字符串或NULL,而主函数应继续分配read()的输出,直到分配了NULL。
我已经看过该程序的许多不同版本,但是它总是最终导致分段错误。我将如何开始调试细分错误?
我已经在下面添加了程序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *read(){
char *line = (char *) malloc (80 * sizeof(char));
fgets(line,80,stdin);
if (line != NULL) {
line[strlen(line)-1] = '\0';
return line;
}
else {
free(line);
return NULL;
}
}
int main()
{
int i=0,j,k,l;
char **arr = (char **) malloc (100 * sizeof(char *));
for (k = 0; k < 100; k++) {
arr[k] = malloc (80 * sizeof(char));
}
while(1){
strcpy(arr[i],read());
if (arr[i]=NULL) break;
i++;
//printf("%s", arr[i]); //DEBUG
}
for (l = 0; l < 100; l++){
free(arr[l]);
}
free(arr);
for (j = i-11; j < i; j++) {
printf("%s\n", arr[j]);
}
printf("\n");
return 0;
}
答案 0 :(得分:1)
在主要
中while(1){
strcpy(arr[i],read());
if (arr[i]=NULL) break;
您永远不会退出循环,因为arr[i]=NULL
没有理由从 read 中得知(由于 read 中的错误),因此您编写 arr 中出现不确定的行为(崩溃)
您不能很好地管理read的文件结尾:
fgets(line,80,stdin);
if (line != NULL) {
除了 malloc 成功
,您需要检查 fgets 的结果,而不是 line 为NULL的情况。不是说line[strlen(line)-1] = '\0';
没用,因为 fgets 放置了最后一个空字符,还好
所以 read 可以是:
char *read(){
char *line = (char *) malloc (80 * sizeof(char));
if (line != NULL) {
if (fgets(line,80,stdin) == NULL) {
free(line);
return NULL;
}
}
return line;
}
由于读取可以返回NULL,因此您需要更改
strcpy(arr[i],read());
并且这也是为什么您同时分配读状态时预分配行的原因吗?当前,您会释放每次读取时分配的内存
似乎最好将循环替换为
while((arr[i] == read()) != NULL)
//printf("%s", arr[i]); //DEBUG
i += 1;
}
并删除行的预分配
另一个问题是,当文件的行数超过100行(或者在很长的时间内可能会切掉某些行)时,这种情况下您会写出 arr 。实际上,您不需要保存太多行,只需要最多保存10行
提案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *read() {
char line[80];
if (fgets(line, 80, stdin) == NULL)
return NULL;
return strdup(line);
}
int main()
{
char * arr[10] = { NULL };
char * p;
int i = 0, n = 0;
while((p = read()) != NULL) {
n += 1;
free(arr[i]);
arr[i] = p;
if (++i == 10)
i = 0;
}
/* get older line index and line count to print */
if (n <= 10)
i = 0;
else
n = 10;
while (n-- != 0) {
puts(arr[i]);
free(arr[i]);
if (++i == 10)
i = 0;
}
return 0;
}
Compilation and execution :
pi@raspberrypi:/tmp/d $ gcc -g -pedantic -Wextra q.c
pi@raspberrypi:/tmp/d $ ./a.out < q.c
n = 10;
while (n-- != 0) {
puts(arr[i]);
if (++i == 10)
i = 0;
}
return 0;
}
请注意,我没有删除\ n是读取行,而是使用 puts ,因此打印了空行,但由于太长而没有剪切读取行
如果文件短于10行:
pi@raspberrypi:/tmp/d $ tail -n 5 q.c | ./a.out
i = 0;
}
return 0;
}
在 valgrind 下:
pi@raspberrypi:/tmp/d $ valgrind ./a.out < q.c
==18496== Memcheck, a memory error detector
==18496== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==18496== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==18496== Command: ./a.out
==18496==
while (n-- != 0) {
puts(arr[i]);
free(arr[i]);
if (++i == 10)
i = 0;
}
return 0;
}
==18496==
==18496== HEAP SUMMARY:
==18496== in use at exit: 0 bytes in 0 blocks
==18496== total heap usage: 43 allocs, 43 frees, 5,699 bytes allocated
==18496==
==18496== All heap blocks were freed -- no leaks are possible
==18496==
==18496== For counts of detected and suppressed errors, rerun with: -v
==18496== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)