[c] 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를 사용하여 constLine 문자열도 올바르게 읽은 것을 알 수 있습니다.

그러나 다음과 같은 기능을 사용하면 :

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

printf는 횡설수설합니다. 왜?



답변

작업이 한 줄씩 읽기 기능을 발명하지 않고 파일을 한 줄씩 읽으려면 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);
}


답변

FILE* filePointer;
int bufferLength = 255;
char buffer[bufferLength];

filePointer = fopen("file.txt", "r");

while(fgets(buffer, bufferLength, filePointer)) {
    printf("%s\n", buffer);
}

fclose(filePointer);


답변

당신의에서 readLine기능, 당신은에 대한 포인터 반환 line(첫 번째 문자로, 엄밀히 말하면 포인터를하지만, 차이는 여기에 무관) 배열. 이 변수는 자동 변수이므로 (즉, “스택”) 함수가 반환 될 때 메모리가 회수됩니다. printf스택에 자체 물건을 넣었 기 때문에 횡설수설 한 것을 볼 수 있습니다 .

함수에서 동적으로 할당 된 버퍼를 반환해야합니다. 당신은 이미 하나를 가지고 있습니다 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() 정의되지 않은 동작을 일으키는 지역 변수에 대한 포인터를 반환합니다.

당신을 돌아 다니려면 :

  1. 호출자 함수에서 변수를 작성하고 주소를 readLine()
  2. line사용을 위한 메모리 할당 malloc()-이 경우line 에는 영구적입니다
  3. 일반적으로 나쁜 습관이지만 전역 변수를 사용하십시오.

답변

fgets()파일 핸들에서 줄을 읽는 데 사용 합니다.


답변

예제에 몇 가지 잘못된 점이 있습니다.

  • printfs에 \ n을 추가하는 것을 잊었습니다. 또한 오류 메시지는 stderr로 이동해야합니다.fprintf(stderr, ....
  • (더 크지 않지만) fgetc()보다는을 사용 하는 것이 좋습니다 getc(). getc()매크로 fgetc()입니다, 적절한 기능입니다
  • getc()반환 int그래서는 ch로 선언되어야한다 int. 와의 비교 EOF가 올바르게 처리 되므로 중요 합니다. 일부 8 비트 문자 세트 0xFF는 유효한 문자로 사용 되며 (ISO-LATIN-1이 예일 수 있음) EOF-1은에 0xFF지정된 경우 char입니다.
  • 라인에 잠재적 인 버퍼 오버 플로우가 있습니다

    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.