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

saneum3님의 프로필 이미지
saneum3

작성한 질문수

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

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

readbooks, readbook2 함수 구현

해결된 질문

작성

·

276

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으로 힙메모리를 새로 할당할 필요가 없다고 느껴, 위와같이 구현하였는데 런타임에러가 생기더라구요. 위와 같은 코드에서 런타임 에러가 나는 이유를 못찾겠습니다.

답변 3

1

안녕하세요.

첫번째 질문. 

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

디버깅을 해보니 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 에 가져가서 사용하고 계세요. 두번째 이유는 찾으셨다고 했는데 이 이유 맞으실까요! 

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

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

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

0

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

안녕하세요!

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

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

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

saneum3님의 프로필 이미지
saneum3

작성한 질문수

질문하기