해결된 질문
작성
·
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 에 가져가서 사용하고 계세요. 두번째 이유는 찾으셨다고 했는데 이 이유 맞으실까요!
디버깅 해보시고 런타임 에러 메세지도 검색해보시면 이유를 대부분 찾을 수 있습니다. 코딩하실 때 디버깅도 꼭 병행해보셨으면 좋겠어요~!
0
아넵
알림을 못봐서 답변이 늦었네요,,; 그리고 두번째 질문에 대한 답은 찾았습니다!
#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
아,, 너무 명쾌하셔서 좀 허무할 정도네요ㅠㅠ; 디버깅에 중요성 다시한번 숙지하도록 하겠습니다. 감사합니다.