C逐行读取文件

我写了这个函数从文件中读取一行:

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我看到constLinestring也得到正确读取。

但是,如果我使用这样的function:

 while (!feof(myFile)) { const char *line = readLine(myFile); printf("%s\n", line); } 

printf输出乱码。 为什么?

如果您的任务不是发明逐行读取function,而是逐行读取文件,则可以使用一个涉及getline()函数的典型代码片段(请参阅手册页):

 #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); } 

在你的readLine函数中,你返回一个指向line数组的指针(严格地说,是指向它的第一个字符的指针,但是这里的差别是不相关的)。 由于它是一个自动variables(即“在堆栈上”),当函数返回时,内存将被回收。 你看到乱码,因为printf已经把自己的东西放在堆栈上。

你需要从函数返回一个dynamic分配的缓冲区。 你已经有一个,它是lineBuffer ; 所有你需要做的是截断它到所需的长度。

  lineBuffer[count] = '\0'; realloc(lineBuffer, count + 1); return lineBuffer; } 

ADDED (响应在注释中的后续问题): 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). */ 
 //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 

readLine()返回指向局部variables的指针,导致未定义的行为。

为了避开你可以:

  1. 在调用函数中创buildvariables并将其地址传递给readLine()
  2. 使用malloc()line分配内存 – 在这种情况下, line是持久的
  3. 使用全局variables,虽然这是一个不好的做法
 FILE* fp; char buffer[255]; fp = fopen("file.txt", "r"); while(fgets(buffer, 255, (FILE*) fp)) { printf("%s\n", buffer); } fclose(fp); 

这个例子有些错误:

  • 您忘记将\ n添加到您的printfs中。 也错误消息应该去stderr即fprintf(stderr, ....
  • (不是一个biggy,但)考虑使用fgetc()而不是getc()getc()是一个macros, fgetc()是一个正确的函数
  • getc()返回一个int所以ch应该被声明为int 。 这是重要的,因为与EOF的比较将被正确处理。 某些8位字符集使用0xFF作为有效字符(ISO-LATIN-1将是一个示例), EOF为-1,如果赋值为char ,则将为0xFF
  • 线路上有潜在的缓冲区溢出

     lineBuffer[count] = '\0'; 

    如果行长度正好是128个字符,那么在执行的时候count是128。

  • 正如其他人所指出的, line是一个本地声明的数组。 你不能返回一个指针。

  • strncpy(count + 1)最多可以复制count + 1字符,但是如果命中'\0'就会终止'\0'因为你将lineBuffer[count]设置为'\0'你知道它永远不会count + 1 。 但是,如果这样做,它不会终止'\0' ,所以你需要这样做。 你经常看到如下内容:

     char buffer [BUFFER_SIZE]; strncpy(buffer, sourceString, BUFFER_SIZE - 1); buffer[BUFFER_SIZE - 1] = '\0'; 
  • 如果你的malloc()一行返回(代替你的本地char数组),你的返回types应该是char* – 删除const

使用fgets()从文件句柄中读取一行。

你应该使用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; } 
 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); } } 

这个如何?

 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'variables在调用函数中被声明,然后被传递,所以你的readLine函数填充预定义的缓冲区并且返回它。 这是大多数C库的工作方式。

还有其他方法,我知道:

  • char line[]定义为静态( static char line[MAX_LINE_LENGTH] – >它将在函数返回后保存它的值)。 – >不好,函数不可重入,竞态条件可能发生 – >如果你从两个线程调用它两次,它会覆盖它的结果
  • malloc()的char line [],并释放它在调用函数 – >太多昂贵的malloc s,并委托责任释放缓冲区到另一个函数(最优雅的解决scheme是调用mallocfree任何缓冲区在相同的function)

顺便说一句,从char*const char*的显式转换是多余的。

btw2,不需要malloc() lineBuffer,只需定义它char lineBuffer[128] ,所以你不需要释放它

btw3不要使用“dynamic大小的堆栈数组”(将数组定义为char arrayName[some_nonconstant_variable] ),如果你不完全知道你在做什么,它只能在C99中工作。

你犯了一个返回指向自动variables的错误。 variables行被分配在堆栈中,只有在函数处于活动状态时才会存在。 你不允许返回一个指针,因为只要它返回,内存将在别处被给出。

 const char* func x(){ char line[100]; return (const char*) line; //illegal } 

为了避免这种情况,你要么返回一个指向堆的内存,例如。 lineBuffer,用户有责任在完成之后调用free()。 或者,您可以要求用户将您作为parameter passing给在其上写入行内容的内存地址。

我想从地面0代码,所以我这样做,逐行阅读字典的字符的内容。

char temp_str [20]; //您可以根据您的要求更改缓冲区大小和文件中单行的长度。

注意我每次读取行时都初始化了带有空字符的缓冲区。这个函数可以是自动的但是因为我需要一个Concept的certificate并且想要devise一个程序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; }