작성
·
199
·
수정됨
1
안녕하세요 이 글은 제가 오개념을 가지고 그냥 운좋게 실행되는 코드를 짜낸것인지 좀 불안한 마음이 역력해서 드리는 질문글입니다.
10:51 부분이며 교수님께서 짜신 read_books2
함수는 (포인터가 널인지 아닌지 체크하는 유효성 검사 코드 같은 것들은 생략했습니다)
void read_books2(const char* filename, struct book** books_dptr, int* n_ptr)
{
FILE* fp = fopen(filename, "r");
fscanf(fp, "%d%*c", n_ptr);
struct book* books = (struct book*)calloc(*n_ptr, sizeof(struct book));
for (int i = 0; i < *n_ptr; ++i)
{
fscanf(fp, "%[^\n]%*c%[^\n]%*c", books[i].name, books[i].author);
}
fclose(fp);
*books_dptr = books;
}
이고, 제가 작성한 코드는
void read_books2(const char* filename, struct book** books_dptr, int* n)
{
FILE* fp = fopen(filename, "r");
fscanf(fp, "%d%*c", n);
*books_dptr = (struct book*)calloc(*n, sizeof(struct book));
for (int i = 0; i < *n; ++i)
{
fscanf(fp, "%[^\n]%*c%[^\n]%*c", (*books_dptr)[i].name, (*books_dptr)[i].author);
}
fclose(fp);
}
입니다. 전체코드는 맨 아래에 있습니다.
교수님께서는 함수 내부에 새로운 구조체 포인터*books
를 만들어서 파일로부터 읽어들인 값들을 정리했고 그 구조체의 주소값을 *books_dptr = books
를 통해 원래 main함수 안에 있던 my_books
로 직접 넘겨주셨습니다.
그런데 저는 매개없이 가져온 주소에 직접 *books_dptr = (struct book*)calloc(*n, sizeof(struct book));
이렇게 메모리를 조정해줬고 (교수님께서는 = 좌변에 직접 새로운 구조체 포인터를 만드셨습니다)
후에 fscanf(fp, "%[^\n]%*c%[^\n]%*c", (*books_dptr)[i].name, (*books_dptr)[i].author);
처럼 txt파일로부터 읽은 것을 함수매개변수를 통해 가져온 주소에 직접 가서 값을 넣었습니다. 혹시 이 방식에서 우려하실 부분은 없으실까요?
감사합니다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define SLEN 101
#define FILE_NAME "books.txt"
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) * n);
if (!my_books)
{
printf("malloc() has failed");
exit(EXIT_FAILURE);
}
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(FILE_NAME, 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();
read_books2(FILE_NAME, &my_books, &n);
//my_books = read_books(FILE_NAME, &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");
fprintf(fp, "%d\n", n);
for (int i = 0; i < n; ++i)
{
fprintf(fp, "%s\n%s\n", books[i].name, books[i].author);
}
fclose(fp);
}
struct book* read_books(const char* filename, int* n)
{
FILE* fp = fopen(filename, "r");
fscanf(fp, "%d%*c", n);
struct book* lits = (struct book*)calloc(*n, sizeof(struct book));
for (int i = 0; i < *n; ++i)
{
fscanf(fp, "%[^\n]%*c%[^\n]%*c", lits[i].name, lits[i].author);
}
fclose(fp);
return lits;
}
void read_books2(const char* filename, struct book** books_dptr, int* n)
{
FILE* fp = fopen(filename, "r");
fscanf(fp, "%d%*c", n);
*books_dptr = (struct book*)calloc(*n, sizeof(struct book));
for (int i = 0; i < *n; ++i)
{
fscanf(fp, "%[^\n]%*c%[^\n]%*c", (*books_dptr)[i].name, (*books_dptr)[i].author);
}
fclose(fp);
}
답변 1
2
안녕하세요, 답변 도우미 Soobak 입니다.
*books_dptr
에 직접 메모리를 할당하고, 데이터를 직접 해당 메모리에 저장하는 방식으로 구현하셨네요.
교수님께서 강의 중 소개해주신 코드는, 함수 내의 포인터 books
를 사용하여 메모리를 할당한 다음, 이 포인터를 외부 포인터 *books_dptr
에 복사합니다.
이러한 방식은 함수 내부에서만 사용할 수 있는 임시 포인터를 만들고, 최종 결과를 외부 포인터에 복사하는 패턴으로, 책임에 대한 분리, 유연성, 오류 처리, 메모리 관리 측면에서 보다 더 장점을 가지고 있습니다.
반면, 질문자님의 접근 방식은 *books_dptr
에 직접 메모리를 할당함으로써, 중간 단계를 생략하여 코드를 간결하게 만들고 직관적으로 작동하게 하지만, 함수의 독립성과 유연성 측면에서는 교수님께서 소개해주신 패턴에 비하여 다소 제한적일 수 있습니다.
개인적으로, 질문자님의 코드도 잘 작동하는 유효한 접근 방식이고, 스스로 학습 과정에서 좋은 궁금증으로 질문을 주셨다고 생각합니다.
어떤 방식을 선택할지는 프로그램의 요구사항, 개발자의 선호, 코드의 유지보수성 등 다양한 부분들을 함께 고려하고, 이를 잘 조율하는 것이 좋은 개발자의 자세라고 생각합니다.
또한, 문법 학습을 마치신 후, 자료구조와 알고리즘 학습, 그리고 다양한 경험을 쌓으시면서,
객체 지향 프로그래밍, 그리고 다양한 프로그래밍 패러다임, 디자인 패턴 등에 대하여 경험하시는 과정을 통해 두 접근 방식의 장/단점을 자연스럽게 깨닫게 되실 것이라고 생각합니다.
정말 감사합니다!!