inflearn logo
강의

講義

知識共有

ホン・ジョンモのついていきながら学ぶC言語

14.14 構造体ファイル入出力の練習問題

readbooks, readbook2 함수 구현

解決済みの質問

364

saneum3

投稿した質問数 8

0

 

 

struct book* read_books(const char* filename, int* n)
{
	FILE* fp = fopen(filename, "r");
	
	if (fp == NULL) {
		fputs("Can't open file.", stderr);
		exit(1);
	}
	
	//struct book* book = (struct book*)malloc(sizeof(struct book) * *n);

	int flag;
	flag = fscanf(fp, "%d%*c", n);
	if (flag != 1) {
		printf("File read failed");
		exit(1);
	}
	
	struct book* book = (struct book*)malloc(sizeof(struct book)* *n);

	if (!book) {
		printf("Malloc() failed.");
		exit(1);
	}

	for (int i = 0; i < *n; i++)
	{
		fscanf(fp, "%[^\n]%*c", book[i].name);
		fscanf(fp, "%[^\n]%*c", book[i].author);
		/*if (flag != 2) {
			printf("File read failed");
			exit(1);
		}*/
	}
	
	fclose(fp);

	return book;
}

안녕하세요!

readbook함수 구현에서, malloc으로 구조체 힙 메모리 할당 코드를 주석으로 처리된 위치에 구현하였는데 계속 런타임 에러가 뜨더라구요. 교수님께서는 위와 같은 위치로 구현하였는데 두 위치상 코드의 차이를 모르겠습니다..

 

void read_book2(const char* filename, struct book** book_dptr, int* n)
{
	FILE* fp = fopen(filename, "r");
	if (fp == NULL) {
		fputs("Can't open file.", stderr);
		exit(1);
	}

	int flag;
	flag = fscanf(fp, "%d%*c", n);
	if (flag != 1) {
		printf("File read failed");
		exit(1);
	}

	for (int i = 0; i < *n; i++)
	{
		fscanf(fp, "%[^\n]%*c", book_dptr[i]->name);
		fscanf(fp, "%[^\n]%*c", book_dptr[i]->author);
	}

	fclose(fp);
}

readbook2함수 구현에서 struct book의 이중포인터를 파라미터로 가져오는거라 malloc으로 힙메모리를 새로 할당할 필요가 없다고 느껴, 위와같이 구현하였는데 런타임에러가 생기더라구요. 위와 같은 코드에서 런타임 에러가 나는 이유를 못찾겠습니다.

c

回答 3

1

sohyun

안녕하세요.

첫번째 질문. 

주석 처리한 부분이 아닌 체크한 부분에서 동적할당을 받으면 에러가 난다고 하셨는데

디버깅을 해보니 main 함수에서 이  book 힙 메모리를 한참 다 쓰고나서 이제 해제하는 free 하는 지점에서 런타임 에러가 발생했습니다.

그 런타임 에러 메세지를 검색해보니 동적할당받은 크기보다 더 많은 메모리를 쓴 후에 free시켜달라고 하면 발생하는 에러네요.

그렇다면 왜 메모리를 더 많이 썼을까 하고 메모리를 더 쓴 부분을 찾아보면 되는데요

찾아보니 여기서 n 을 0 으로 만들어버린 후에 read_books 를 실행했기 때문임을 알 수 있네요.

그렇기 때문에 체크한 부분에서는 n = 0 인 상태로 동적할당을 받은 셈이나 마찬가지구요. 그러니 0 사이즈로 할당받은거라 할당받은건 아무것도 없는것이나 마찬가지인데도 book[i].name 이런식으로 오버해서 한참 쓰다가 free 시키려고 하니 에러가 났던것입니다. 

주석된 부분에서 동적할당을 받았다면 위에 fscanf(fp ... n) 이 부분에서 n = 3 으로 만든 후에 동적할당을 받으므로 3 크기로 동적할당을 받게 되기에 아무 문제가 없었던거구요.  그러니 강의와 똑같이 원래대로 주석처리한 곳에서 동적할당 받는게 좋겠습니다.

두번째 질문. 

이 또한 비슷한 이유입니다.

my_books 를 이미 free 시켰는데 이걸 read_books2 에 가져가서 사용하고 계세요. 두번째 이유는 찾으셨다고 했는데 이 이유 맞으실까요! 

디버깅 해보시고 런타임 에러 메세지도 검색해보시면 이유를 대부분 찾을 수 있습니다. 코딩하실 때 디버깅도 꼭 병행해보셨으면 좋겠어요~! 

0

saneum3

아,, 너무 명쾌하셔서 좀 허무할 정도네요ㅠㅠ;  디버깅에 중요성 다시한번 숙지하도록 하겠습니다.  감사합니다.

0

saneum3

아넵

알림을 못봐서 답변이 늦었네요,,; 그리고 두번째 질문에 대한 답은 찾았습니다!

#include <stdio.h>
#include <stdlib.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_book2(const char* filename, struct book** book_dptr, int* n);

int main()
{
	int temp;
	int n = 3;

	struct book* my_books = (struct book*)malloc(sizeof(struct book) * n);
	if (!my_books) {
		printf("Malloc failed");
		exit(1);
	}
	
	my_books[0] = (struct book){ "The great gatsby","F. scott" };
	my_books[1] = (struct book){ "Hamlet","William shakespere" };
	my_books[2] = (struct book){ "The odysey","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_book2("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 = fopen(filename, "w");

	if (fp == NULL) {
		fputs("Can't open file.", stderr);
		exit(1);
	}

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

	for (int i = 0; i < n; i++)
	{
		fputs(books[i].name, fp);
		fputc('\n', fp);
		fputs(books[i].author, fp);
		fputc('\n', fp);
	}
	fclose(fp);
}

struct book* read_books(const char* filename, int* n)
{
	FILE* fp = fopen(filename, "r");
	
	if (fp == NULL) {
		fputs("Can't open file.", stderr);
		exit(1);
	}
	
	//struct book* book = (struct book*)malloc(sizeof(struct book) * *n);

	int flag;
	flag = fscanf(fp, "%d%*c", n);
	if (flag != 1) {
		printf("File read failed");
		exit(1);
	}
	
	struct book* book = (struct book*)malloc(sizeof(struct book)* *n);

	if (!book) {
		printf("Malloc() failed.");
		exit(1);
	}

	for (int i = 0; i < *n; i++)
	{
		flag = fscanf(fp, "%[^\n]%*c", book[i].name);
		flag = fscanf(fp, "%[^\n]%*c", book[i].author);
		/*if (flag != 2) {
			printf("File read failed");
			exit(1);
		}*/
	}
	
	fclose(fp);

	return book;
}

void read_book2(const char* filename, struct book** book_dptr, int* n)
{
	FILE* fp = fopen(filename, "r");
	if (fp == NULL) {
		fputs("Can't open file.", stderr);
		exit(1);
	}

	int flag;
	flag = fscanf(fp, "%d%*c", n);
	if (flag != 1) {
		printf("File read failed");
		exit(1);
	}

	for (int i = 0; i < *n; i++)
	{
		fscanf(fp, "%[^\n]%*c", book_dptr[i]->name);
		fscanf(fp, "%[^\n]%*c", book_dptr[i]->author);
	}

	fclose(fp);
}

 

 

 

 

0

sohyun

안녕하세요!

혹시 디버깅은 해보셨을까요?

원인을 찾으려면 제가 디버깅 해봐야할 것 같아서 

main 함수를 비롯한 전체 코드와 txt 파일 내용 주시면 감사하겠습니다. 

Export template 안됨

1

23

2

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

1

55

3

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

1

56

2

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

1

54

2

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

1

49

1

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

1

73

2

12.12 헤더 관련 질문

1

60

2

Visual Studio Community 2026 사용 문의

1

138

2

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

1

61

2

getchar(), putchar()

1

93

3

강의자리ㅛ

1

80

2

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

1

114

2

소스파일안에 여러 파일

1

76

2

F5와 F7의 차이

1

77

2

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

1

58

2

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

1

70

1

Step over 기능 문의

1

53

2

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

1

76

2

int main 함수 관련 오류 문의

1

67

2

13.4 words[0]

0

61

2

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

1

62

2

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

1

65

2

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

1

53

2

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

1

54

2