inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

홍정모의 따라하며 배우는 C언어

14.14 구조체 파일 입출력 연습문제

struct book* read_books 예제에서 쓰인 malloc()에 대해 질문합니다.

해결된 질문

252

thd2tn

작성한 질문수 27

0

struct book* read_books(const char* filename, int* n)

{

FILE* fp;

int count;

char buffer[SLEN] = { '\0', };

struct book* books;

 

if ((fp = fopen(filename, "r")) == NULL)

{

fprintf(stderr, "Can't open \"%s\" file.\n", filename);

 

exit(EXIT_FAILURE);

}

 

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

count = atoi(buffer);

*n = count;

 

books = (struct book*)malloc(sizeof(struct book) * count);

 

if (!books) 

{

printf("Malloc failed");

exit(1);

}

 

for (int i = 0; i < count; ++i)

{

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

strcpy(books[i].name, buffer);

 

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

strcpy(books[i].author, buffer);

}

 

fclose(fp);

 

return books;

}

 

제가 작성한 read_books 코드입니다. fscanf()도 %[^\n]%*c 가 사용되는지 몰라서 string.h을 이용해서 저렇게 작성을 하였는데
빌드도 잘 되고 작동도 잘 되는데 strcpy(books[i].name, buffer); 에서 warning이 뜹니다. 정확히

C6385 Reading invalid data from 'books':  the readable size is 'sizeof(book)*count' bytes, but '404' bytes may be read.

이렇게 뜨는데 코드를 바꿔가면서 알아보니깐 books = (struct book*)malloc(sizeof(struct book) * count); 이 부분에서
count를 상수로 바꾸면 오류가 안 뜹니다. 또 교수님이 calloc()을 쓰시길래 calloc()으로 바꿨더니 상수로 바꿨을 때처럼 오류가 사라졌습니다. 그 이유가 궁금합니다. 

또 교수님께서 calloc()에서 size_t _count부분에 size를 size_t _size부분에 count를 넣으셨는데 이 부분을 바꿔도
동적할당된 힙 메모리를 가리키는 포인터를 배열처럼 사용하는데 전혀 문제가 발생하지 않는지, 또 그 이유는 무엇인지 궁금합니다.

c

답변 2

1

안소

 

1. count 는 런타임에 값이 결정되며 런타임 중에 값이 계속해서 변할 수 있는 일반 변수이기에 워닝을 띄워주는 듯 합니다. 워닝을 띄우는 시점은 컴파일 타임인데 사실 컴파일 타임엔 진짜 sizeof(book)*count 가 404byte 를 넘어 오버플로우가 될지는 알 수가 없구요, 컴파일 타임에 체크해줄 수 없으니 그냥 조심하라는 경고 정도로 생각해주시면 될 것 같습니다! count 가 상수라면 컴파일 타임에도 404byte 를 넘지 않을지 확실하게 알 수가 있으니까 워닝이 없는 것으로 생각이 되구요, calloc 은 두 개의 인자를 받음으로써 오버플로우 될 수 있을지를 미리 체크할 수 있다고 합니다. https://stackoverflow.com/questions/4083916/two-arguments-to-calloc

 

2. 이 부분은 코드에서도 강의에서도 제가 못 찾겠네요 ㅠ (질문 주실 때 강의 시간대 함께 꼭 남겨주실 것을 부탁드립니다!) 근데 아마 질문해주신 것만 봐서는 포인터를 배열처럼 사용하는 것과는 전혀 상관없어 보입니다. 그냥 포인터는 원래 배열처럼 [] 연산자를 사용할 수 있습니다. [] 도 곧 포인터 산술연산이니까요!

0

thd2tn

항상 감사합니다!!

1

안소

안녕하세요!

저는 해당 워닝이 발생하지 않는데 혹시 전체 코드 주실 수 있을까요?

0

thd2tn

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

#include <conio.h>

 

#define SLEN 101

 

struct book

{

char name[SLEN];

char author[SLEN];

};

 

void print_books(const struct book* books, int n);

void write_books(const char* filename, const struct book* books, int n);

struct book* read_books(const char* filename, int* n);

void read_books2(const char* filename, struct book** books_dptr, int* n);

 

int main()

{

int temp;

int n = 3;

 

struct book* my_books = (struct book*)malloc(sizeof(struct book) * 3);

 

if (!my_books) {

printf("Malloc failed");

exit(1);

}

 

my_books[0] = (struct book){ "The Great Gatsby", "F. Scott Fitzgerald" };

my_books[1] = (struct book){ "Hamlet", "William Shakespeare" };

my_books[2] = (struct book){ "The Odyssey", "Homer" };

 

print_books(my_books, n);

 

printf("\nWriting to a file.\n");

write_books("books.txt", my_books, n);

free(my_books);

n = 0;

printf("Done.\n");

 

printf("\nPress any key to read data from a file.\n\n");

temp = _getch();

 

my_books = read_books("books.txt", &n);

//read_books2("books.txt", &my_books, &n);

print_books(my_books, n);

free(my_books);

n = 0;

 

return 0;

}

 

void print_books(const struct book* books, int n)

{

for (int i = 0; i < n; ++i)

{

printf("Book %d : \"%s\" written by \"%s\"\n",

i + 1, books[i].name, books[i].author);

}

}

 

void write_books(const char* filename, const struct book* books, int n)

{

FILE* fp;

 

if ((fp = fopen(filename, "w")) == NULL)

{

fprintf(stderr, "Can't open \"%s\" file.\n", filename);

 

exit(EXIT_FAILURE);

}

 

fprintf(fp, "%d\n", n);

 

for (int i = 0; i < n; ++i)

{

fputs(books[i].name, fp);

fprintf(fp, "\n");

fputs(books[i].author, fp);

fprintf(fp, "\n");

}

 

fclose(fp);

}

 

struct book* read_books(const char* filename, int* n)

{

FILE* fp;

int count;

char buffer[SLEN] = { '\0', };

struct book* books;

 

if ((fp = fopen(filename, "r")) == NULL)

{

fprintf(stderr, "Can't open \"%s\" file.\n", filename);

 

exit(EXIT_FAILURE);

}

 

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

count = atoi(buffer);

*n = count;

 

books = (struct book*)malloc(sizeof(struct book) * count);

 

if (!books) 

{

printf("Malloc failed");

exit(1);

}

 

for (int i = 0; i < count; ++i)

{

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

strcpy(books[i].name, buffer);

 

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

strcpy(books[i].author, buffer);

}

 

fclose(fp);

 

return books;

}

 

void read_books2(const char* filename, struct book** books_dptr, int* n) 

{

FILE* fp;

int count;

 

char buffer[SLEN] = { '\0', };

 

if ((fp = fopen(filename, "r")) == NULL)

{

fprintf(stderr, "Can't open \"%s\" file.\n", filename);

 

exit(EXIT_FAILURE);

}

 

fgets(buffer, SLEN, fp);

 

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

 

count = atoi(buffer);

*n = count;

 

for (int i = 0; i < count; ++i)

{

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == '\n')

buffer[i] = '\0';

}

strcpy((*books_dptr)[i].name, buffer);

 

fgets(buffer, SLEN, fp);

for (int i = 0; i < SLEN; ++i)

{

if (buffer[i] == "\n")

buffer[i] = '\0';

}

 

strcpy((*books_dptr)[i].author, buffer);

}

 

fclose(fp);

}

 

여기 있습니다!

Export template 안됨

1

63

2

완전히 똑같이 따라해도 exe파일이 안만들어져서 실행이 안됩니다.

1

88

3

main 함수에서 왜 int만 선언이 되는걸까요

1

78

2

8비트 2진수 변환시 왜 1을 더해야하나요?

1

75

2

혹시 강의를 빠르게 수강하려면 어디서부터 듣는게 좋을까요?

1

78

1

프로토타입과 함수간의 인자 불일치

1

87

2

12.12 헤더 관련 질문

1

74

2

Visual Studio Community 2026 사용 문의

1

170

2

Q. 15:30, 부호가 있는 8비트 정수 질문

1

72

2

getchar(), putchar()

1

111

3

강의자리ㅛ

1

93

2

비주얼스튜디오코드로 공부해도 상관없나요?

1

127

2

소스파일안에 여러 파일

1

87

2

F5와 F7의 차이

1

90

2

c = TWO * (a+b); 에서 a와 b는?

1

67

2

; 세미콜론을 붙이는 기준에 문의

1

78

1

Step over 기능 문의

1

64

2

2.6 강의 따옴표 출력 규칙 문의

1

87

2

int main 함수 관련 오류 문의

1

76

2

13.4 words[0]

0

73

2

11.7 함수를 구현해 봤습니다.

1

67

2

11.6 직접 strcmp와 strncmp를 구현해 보았습니다.

1

71

2

11.6 my_strcat과 my_strncat을 구현해봤습니다.

1

60

2

11.6 fit_str함수를 구현해 봤습니다.

1

59

2