我写了这个函数来从文件中读取一行:
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输出乱码。为什么呢?
答案 0 :(得分:258)
如果您的任务不是要发明逐行读取功能,而只是逐行读取文件,则可以使用涉及getline()
功能的典型代码段(请参阅手册)页面here):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
答案 1 :(得分:20)
在你的readLine
函数中,返回一个指向line
数组的指针(严格来说,指向第一个字符的指针,但这里的差异无关紧要)。由于它是一个自动变量(即它在“堆栈中”),因此在函数返回时回收内存。你看到了胡言乱语,因为printf
已将自己的东西放在堆栈上。
您需要从函数返回动态分配的缓冲区。你已经有一个,lineBuffer
;你所要做的就是将它截断到所需的长度。
lineBuffer[count] = '\0';
realloc(lineBuffer, count + 1);
return lineBuffer;
}
已添加(对评论中的后续问题的回复):readLine
返回指向组成该行的字符的指针。此指针是您处理行内容所需的。当你使用完这些字符所占用的内存时,它也必须传递给free
。以下是您使用readLine
函数的方法:
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
You can't use the value of `line` again (though you can assign a new value
to the `line` variable if you want). */
答案 2 :(得分:17)
FILE* fp;
char buffer[255];
fp = fopen("file.txt", "r");
while(fgets(buffer, 255, (FILE*) fp)) {
printf("%s\n", buffer);
}
fclose(fp);
答案 3 :(得分:14)
//open and get the file handle
FILE* fh;
fopen_s(&fh, filename, "r");
//check if file exists
if (fh == NULL){
printf("file does not exists %s", filename);
return 0;
}
//read line by line
const size_t line_size = 300;
char* line = malloc(line_size);
while (fgets(line, line_size, fh) != NULL) {
printf(line);
}
free(line); // dont forget to free heap memory
答案 4 :(得分:9)
readLine()
返回指向局部变量的指针,这会导致未定义的行为。
到处走走可以:
readLine()
line
为malloc()
分配内存 - 在这种情况下line
将是持久的答案 5 :(得分:5)
使用fgets()
从文件句柄中读取一行。
答案 6 :(得分:4)
完整的fgets()
解决方案:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 256
int main(void)
{
FILE* fp;
fp = fopen("file.txt", "r");
if (fp == NULL) {
perror("Failed: ");
return 1;
}
char buffer[MAX_LEN];
// -1 to allow room for NULL terminator for really long string
while (fgets(buffer, MAX_LEN - 1, fp))
{
// Remove trailing newline
buffer[strcspn(buffer, "\n")] = 0;
printf("%s\n", buffer);
}
fclose(fp);
return 0;
}
输出:
First line of file
Second line of file
Third (and also last) line of file
请记住,如果您想读取标准输入(而不是本例中的文件),那么您要做的就是传递stdin
作为fgets()
方法的第三个参数,例如这个:
while(fgets(buffer, MAX_LEN - 1, stdin))
附录
答案 7 :(得分:4)
示例有些问题:
fprintf(stderr, ....
fgetc()
而不是getc()
。 getc()
是一个宏,fgetc()
是一个正确的函数getc()
会返回int
,因此ch
应声明为int
。这很重要,因为与EOF
的比较将得到正确处理。一些8位字符集使用0xFF
作为有效字符(ISO-LATIN-1将是一个示例)并且EOF
为-1,如果分配给{0xFF
将char
1}}。行
处可能存在缓冲区溢出lineBuffer[count] = '\0';
如果该行长度正好为128个字符,则count
在执行时为128。
正如其他人所指出的那样,line
是一个本地声明的数组。你不能返回指向它的指针。
strncpy(count + 1)
最多会复制count + 1
个字符,但如果点击'\0'
则会终止。因为您将lineBuffer[count]
设置为'\0'
,您知道它会永远不会到count + 1
。但是,如果确实如此,则不会终止'\0'
,因此您需要执行此操作。您经常会看到如下内容:
char buffer [BUFFER_SIZE];
strncpy(buffer, sourceString, BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '\0';
如果您malloc()
要返回一行(代替您的本地char
数组),则返回类型应为char*
- 删除const
。
答案 8 :(得分:3)
这是我的几个小时......逐行阅读整个文件。
char * readline(FILE *fp, char *buffer)
{
int ch;
int i = 0;
size_t buff_len = 0;
buffer = malloc(buff_len + 1);
if (!buffer) return NULL; // Out of memory
while ((ch = fgetc(fp)) != '\n' && ch != EOF)
{
buff_len++;
void *tmp = realloc(buffer, buff_len + 1);
if (tmp == NULL)
{
free(buffer);
return NULL; // Out of memory
}
buffer = tmp;
buffer[i] = (char) ch;
i++;
}
buffer[i] = '\0';
// Detect end
if (ch == EOF && (i == 0 || ferror(fp)))
{
free(buffer);
return NULL;
}
return buffer;
}
void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
puts(s);
free(s);
printf("\n");
}
}
int main()
{
char *fileName = "input-1.txt";
FILE* file = fopen(fileName, "r");
lineByline(file);
return 0;
}
答案 9 :(得分:2)
void readLine(FILE* file, char* line, int limit)
{
int i;
int read;
read = fread(line, sizeof(char), limit, file);
line[read] = '\0';
for(i = 0; i <= read;i++)
{
if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
{
line[i] = '\0';
break;
}
}
if(i != read)
{
fseek(file, i - read + 1, SEEK_CUR);
}
}
这个怎么样?
答案 10 :(得分:1)
您应该使用ANSI函数来读取一行,例如。与fgets。在调用之后,你需要在调用上下文中使用free(),例如:
...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...
const char *readLine(FILE *file)
{
char *lineBuffer=calloc(1,1), line[128];
if ( !file || !lineBuffer )
{
fprintf(stderr,"an ErrorNo 1: ...");
exit(1);
}
for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
{
if( strchr(line,'\n') ) *strchr(line,'\n')=0;
lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
if( !lineBuffer )
{
fprintf(stderr,"an ErrorNo 2: ...");
exit(2);
}
}
return lineBuffer;
}
答案 11 :(得分:1)
实现读取文件的方法,并从文件中获取内容(input1.txt)
#include <stdio.h>
#include <stdlib.h>
void testGetFile() {
// open file
FILE *fp = fopen("input1.txt", "r");
size_t len = 255;
// need malloc memory for line, if not, segmentation fault error will occurred.
char *line = malloc(sizeof(char) * len);
// check if file exist (and you can open it) or not
if (fp == NULL) {
printf("can open file input1.txt!");
return;
}
while(fgets(line, len, fp) != NULL) {
printf("%s\n", line);
}
free(line);
}
希望这有帮助。快乐的编码!
答案 12 :(得分:1)
const char *readLine(FILE *file, char* line) {
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);
return line;
}
char linebuffer[256];
while (!feof(myFile)) {
const char *line = readLine(myFile, linebuffer);
printf("%s\n", line);
}
请注意,'line'变量在调用函数中声明然后传递,因此readLine
函数填充预定义缓冲区并返回它。这是大多数C库的工作方式。
还有其他方法,我知道:
char line[]
定义为静态
(static char line[MAX_LINE_LENGTH]
- &GT;从函数返回后它会保持它的值)。 - &GT;坏,
该函数不可重入,并且
可能发生竞争条件 - &gt;如果你
它从两个线程中调用两次
将覆盖它的结果malloc()
char行[],和
在调用函数中释放它 - &gt;
太多昂贵的malloc
s,以及
委托将缓冲区释放到另一个函数的责任(最优雅的解决方案是在同一函数中的任何缓冲区上调用malloc
和free
)顺便说一下,从char*
到const char*
的“明确”投射是多余的。
btw2,没有必要malloc()
lineBuffer,只需定义它char lineBuffer[128]
,所以你不需要释放它
btw3不使用'动态大小的堆栈数组'(将数组定义为char arrayName[some_nonconstant_variable]
),如果你不确切知道你在做什么,它只适用于C99。
答案 13 :(得分:0)
我想从地面0开始编码,所以我这样做是为了逐行阅读字典的内容。
char temp_str [20]; //您可以根据需要更改缓冲区大小和文件中单行的长度。
注意每次读行时我都用Null字符初始化缓冲区。这个函数可以自动化但是因为我需要一个概念证明并想设计一个Byte By Byte程序
#include<stdio.h>
int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
i=0;
char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}
答案 14 :(得分:0)
您错误地将指针返回到自动变量。 变量行在堆栈中分配,只有在函数存在时才存在。 不允许你返回指向它的指针,因为只要它返回,内存就会在其他地方给出。
const char* func x(){
char line[100];
return (const char*) line; //illegal
}
为了避免这种情况,你要么返回一个驻留在堆上的内存的指针,例如。 lineBuffer 并且用户有责任在完成后调用free()。 或者,您可以要求用户将您作为参数传递给您,以便在其中写入行内容。
答案 15 :(得分:0)
我的工具从头开始
FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);
size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
bytes_read = strlen(buf);
// if line length larger than size of line buffer
if (linesize + bytes_read > nbytes) {
char *tmp = line;
nbytes += nbytes / 2;
line = (char *) malloc(nbytes);
memcpy(line, tmp, linesize);
free(tmp);
}
memcpy(line + linesize, buf, bytes_read);
linesize += bytes_read;
if (feof(pFile) || buf[bytes_read-1] == '\n') {
handle_line(line);
linesize = 0;
memset(line, '\0', nbytes);
}
}
free(buf);
free(line);
答案 16 :(得分:-1)
提供可移植且通用的getdelim
函数,通过msvc,clang和gcc通过测试。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
ssize_t
portabl_getdelim(char ** restrict linep,
size_t * restrict linecapp,
int delimiter,
FILE * restrict stream) {
if (0 == *linep) {
*linecapp = 8;
*linep = malloc(*linecapp);
if (0 == *linep) {
return EOF;
}
}
ssize_t linelen = 0;
int c = 0;
char *p = *linep;
while (EOF != (c = fgetc(stream))) {
if (linelen == (ssize_t) *linecapp - 1) {
*linecapp <<= 1;
char *p1 = realloc(*linep, *linecapp);
if (0 == *p1) {
return EOF;
}
p = p1 + linelen;
}
*p++ = c;
linelen++;
if (delimiter == c) {
*p = 0;
return linelen;
}
}
return EOF == c ? EOF : linelen;
}
int
main(int argc, char **argv) {
const char *filename = "/a/b/c.c";
FILE *file = fopen(filename, "r");
if (!file) {
perror(filename);
return 1;
}
char *line = 0;
size_t linecap = 0;
ssize_t linelen;
while (0 < (linelen = portabl_getdelim(&line, &linecap, '\n', file))) {
fwrite(line, linelen, 1, stdout);
}
if (line) {
free(line);
}
fclose(file);
return 0;
}