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

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输出胡言乱语。为什么?


当前回答

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

你可以:

在调用函数中创建变量,并将其地址传递给readLine() 使用malloc()为行分配内存——在这种情况下,行将是持久的 使用全局变量,尽管这通常是一个不好的做法

其他回答

我想要一个代码从地面0,所以我这样做,逐行读取字典的单词的内容。

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

注意,每次读取line时,我都将缓冲区初始化为Null字符。这个功能可以自动化,但因为我需要一个概念的证明,并想要一个字节一个字节地设计程序

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

在readLine函数中,返回一个指向行数组的指针(严格地说,是指向该行数组第一个字符的指针,但这里的区别无关紧要)。由于它是一个自动变量(即,它“在堆栈上”),当函数返回时,内存将被回收。你看到的是乱七八糟的东西,因为printf把它自己的东西放到了堆栈上。

您需要从函数返回一个动态分配的缓冲区。你已经有一个了,它是lineBuffer;你所要做的就是把它截断成所需的长度。

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

ADDED(对评论中后续问题的回应):readLine返回一个指向组成该行的字符的指针。这个指针是处理该行内容所需要的指针。当你用完这些字符占用的内存时,你也必须通过它来释放内存。下面是如何使用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). */

如果你的任务不是发明逐行读取函数,而只是逐行读取文件,你可以使用一个典型的代码片段,包括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()返回指向局部变量的指针,这会导致未定义的行为。

你可以:

在调用函数中创建变量,并将其地址传递给readLine() 使用malloc()为行分配内存——在这种情况下,行将是持久的 使用全局变量,尽管这通常是一个不好的做法

我的工具从头开始:

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