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的指针,导致未定义的行为。
为了避开你可以:
- 在调用函数中创buildvariables并将其地址传递给
readLine()
- 使用
malloc()
为line
分配内存 – 在这种情况下,line
是持久的 - 使用全局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是调用malloc
和free
任何缓冲区在相同的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; }