我写了这个函数来从文件中读取一行:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
该函数正确读取文件,并使用printf我看到constLine字符串也正确读取 .
但是,如果我使用这个功能,例如像这样:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
printf输出乱码 . 为什么?
15 回答
如果你的任务不是发明逐行读取功能,而只是逐行读取文件,你可以使用涉及
getline()
函数的典型代码片段(参见手册页here):在
readLine
函数中,返回一个指向line
数组的指针(严格来说,指向第一个字符的指针,但这里的差异无关紧要) . 由于's an automatic variable (i.e., it' s“在堆栈上”),当函数返回时回收内存 . 你看到了胡言乱语,因为printf
把自己的东西放在了堆栈上 .您需要从函数返回动态分配的缓冲区 . 你已经拥有一个,它是
lineBuffer
;你所要做的就是将它截断到所需的长度 .ADDED (对评论中的后续问题的回复):
readLine
返回指向组成该行的字符的指针 . 此指针是您处理行内容所需的 . 当你've finished using the memory taken by these characters. Here'如何使用readLine
函数时,你也必须传递给free
:readLine()
返回指向局部变量的指针,这会导致未定义的行为 .您可以:
在调用函数中创建变量并将其地址传递给
readLine()
使用
malloc()
为line
分配内存 - 在这种情况下line
将是持久的使用全局变量,虽然这通常是一种不好的做法
使用fgets()从文件句柄中读取一行 .
这个例子有些不对劲:
你忘了在你的printfs上添加\ n . 错误消息也应该发送到stderr,即
fprintf(stderr, ....
(不是大傻子但是)考虑使用
fgetc()
而不是getc()
.getc()
是一个宏,fgetc()
是一个正常的函数getc()
返回int
,因此ch
应声明为int
. 这很重要,因为与EOF
的比较将得到正确处理 . 一些8位字符集使用0xFF
作为有效字符(ISO-LATIN-1将是一个示例),EOF
(-1),如果分配给char
,则为0xFF
.该行可能存在缓冲区溢出
如果该行长度正好为128个字符,则
count
在执行点处为128 .正如其他人所指出的那样,
line
是一个本地声明的数组 . 您无法返回指向它的指针 .strncpy(count + 1)
将最多复制count + 1
个字符,但如果它命中'\0'
则会终止因为你将lineBuffer[count]
设置为'\0'
,你知道它永远不会到达count + 1
. 但是,如果确实如此,它将不会终止'\0'
,所以你需要这样做 . 您经常会看到如下内容:malloc()
返回一行(代替你的本地char
数组),你的返回类型应为char*
- 删除const
.这个如何?
这是我几个小时......逐行读取整个文件 .
请注意'line'变量在调用函数中声明然后传递,因此
readLine
函数填充预定义缓冲区并返回它 . 这是大多数C库的工作方式 .还有其他方法,我知道:
将
char line[]
定义为静态(static char line[MAX_LINE_LENGTH]
- >它会保持's value AFTER returning from the function). -> bad, the function is not reentrant, and race condition can occur -> if you call it twice from two threads, it will overwrite it'的结果malloc()
使用char行[],并在调用函数中释放它 - >太多昂贵的malloc
,并且将责任委托给另一个函数释放缓冲区(最优雅的解决方案是在任何缓冲区中调用malloc
和free
)功能相同)btw,'explicit'从
char*
到const char*
的铸造是多余的 .btw2,没有必要
malloc()
lineBuffer,只需定义它char lineBuffer[128]
,所以你不需要释放它btw3不使用'dynamic sized stack arrays'(将数组定义为
char arrayName[some_nonconstant_variable]
),如果你不确切知道你在做什么,它只适用于C99 .您应该使用ANSI函数来读取一行,例如 . 与fgets . 在调用之后,你需要在调用上下文中使用free(),例如:
实现读取和从文件中获取内容的方法(input1.txt)
希望这有帮助 . 快乐的编码!
你犯了一个返回指向自动变量的指针的错误 . 变量行在堆栈中分配,只有在函数存在时才存在 . 您不能返回指向它的指针,因为只要它返回,内存就会在其他地方给出 .
为了避免这种情况,你要么返回一个驻留在堆上的内存的指针,例如 . lineBuffer,用户有责任在完成后调用free() . 或者,您可以要求用户将您作为参数传递给您在其上写入行内容的内存地址 .
我想要一个来自地面0的代码所以我这样做是为了逐行读取字典的内容 .
char temp_str [20]; //您可以根据您的要求更改缓冲区大小和文件中单行的长度 .
Note 我每次读行时都用Null字符初始化缓冲区 . 这个函数可以自动化但是因为我需要一个概念证明并且想要设计一个Byte By Byte程序
我从头开始实现: