인프런 커뮤니티 질문&답변

thd2tn님의 프로필 이미지
thd2tn

작성한 질문수

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

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

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

해결된 질문

작성

·

209

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를 넣으셨는데 이 부분을 바꿔도
동적할당된 힙 메모리를 가리키는 포인터를 배열처럼 사용하는데 전혀 문제가 발생하지 않는지, 또 그 이유는 무엇인지 궁금합니다.

답변 2

1

 

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

 

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

thd2tn님의 프로필 이미지
thd2tn
질문자

항상 감사합니다!!

1

안녕하세요!

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

thd2tn님의 프로필 이미지
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);

}

 

여기 있습니다!

thd2tn님의 프로필 이미지
thd2tn

작성한 질문수

질문하기