C언어는 강력한 파일 처리 기능을 제공하며, 파일 포인터를 사용하여 바이너리 데이터를 효율적으로 저장하고 읽어올 수 있습니다. 본 기사에서는 파일 포인터의 기본 개념부터 실제 사용 예시까지 다루며, 바이너리 데이터를 처리하는 방법을 단계적으로 설명합니다. 이를 통해 C언어에서 효율적이고 안전하게 데이터를 관리하는 방법을 익힐 수 있습니다.
파일 포인터와 기본 개념
C언어에서 파일 포인터는 파일과 프로그램 간의 데이터를 읽고 쓰는 연결 고리 역할을 합니다. 파일 포인터는 FILE
타입의 포인터로 선언되며, 파일의 위치와 상태를 추적하는 데 사용됩니다.
파일 포인터란?
파일 포인터는 stdio.h
헤더 파일에 정의된 구조체인 FILE
에 대한 포인터입니다. 이를 통해 프로그램은 파일을 열고, 데이터에 접근하고, 파일을 닫는 작업을 수행할 수 있습니다.
파일 포인터의 필요성
- 파일에서 데이터를 효율적으로 읽거나 쓸 수 있도록 지원
- 파일 작업의 위치를 추적하여 특정 위치에서 작업 가능
- 바이너리 데이터와 텍스트 데이터를 모두 처리 가능
파일 포인터 선언
파일 포인터는 다음과 같이 선언됩니다.
FILE *fp;
fp
는 파일을 가리키는 포인터로, 이후 파일 열기 함수(fopen
)를 통해 초기화됩니다.
파일 포인터와 파일 작업
파일 포인터를 사용하면 다음과 같은 작업을 수행할 수 있습니다.
- 파일 열기 (
fopen
) - 파일에 데이터 쓰기 (
fwrite
) - 파일에서 데이터 읽기 (
fread
) - 파일 닫기 (
fclose
)
파일 포인터를 활용하면 C언어에서 강력한 데이터 저장 및 처리 기능을 구현할 수 있습니다.
fopen과 파일 모드
파일 포인터를 사용하려면 먼저 파일을 열어야 하며, 이를 위해 fopen
함수를 사용합니다. fopen
함수는 파일의 경로와 파일 모드를 입력받아 파일 포인터를 반환합니다.
fopen 함수의 사용법
fopen
함수의 기본 문법은 다음과 같습니다:
FILE *fopen(const char *filename, const char *mode);
- filename: 열고자 하는 파일의 경로와 이름을 지정합니다.
- mode: 파일을 여는 방식(모드)을 지정하는 문자열입니다.
파일 모드의 종류
파일 모드는 파일을 읽기, 쓰기, 추가 모드로 열거나 텍스트와 바이너리 데이터를 구분하는 역할을 합니다.
- r: 읽기 모드로 파일을 엽니다. 파일이 존재하지 않으면 오류가 발생합니다.
- w: 쓰기 모드로 파일을 엽니다. 기존 파일이 있으면 내용을 덮어씁니다.
- a: 추가 모드로 파일을 엽니다. 기존 파일 끝에 데이터를 추가합니다.
- rb, wb, ab: 바이너리 데이터 처리를 위한 모드로 각각 읽기, 쓰기, 추가에 사용됩니다.
예제 코드
다음은 fopen
을 사용하여 파일을 열고 닫는 간단한 예제입니다:
#include <stdio.h>
int main() {
FILE *fp;
// 바이너리 쓰기 모드로 파일 열기
fp = fopen("data.bin", "wb");
if (fp == NULL) {
printf("파일을 열 수 없습니다.\n");
return 1;
}
// 파일 닫기
fclose(fp);
return 0;
}
파일 열기 실패 처리
파일을 열 수 없는 경우 fopen
은 NULL
을 반환합니다. 따라서 항상 파일 열기 성공 여부를 확인하는 것이 중요합니다.
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
적절한 파일 모드와 에러 처리를 통해 안정적으로 파일 작업을 수행할 수 있습니다.
fwrite를 이용한 바이너리 데이터 저장
fwrite
함수는 데이터를 바이너리 형식으로 파일에 저장하는 데 사용됩니다. 이 함수는 배열, 구조체, 또는 기타 복합 데이터를 효율적으로 저장할 수 있어 C언어에서 바이너리 데이터 처리를 가능하게 합니다.
fwrite 함수의 문법
fwrite
함수의 기본 문법은 다음과 같습니다:
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
- ptr: 파일에 저장할 데이터의 시작 주소를 가리킵니다.
- size: 저장할 데이터의 단위 크기(바이트)를 지정합니다.
- count: 저장할 데이터 단위의 개수를 지정합니다.
- stream: 데이터를 저장할 파일 포인터를 지정합니다.
fwrite의 반환값
fwrite
는 성공적으로 쓰여진 데이터 단위의 개수를 반환합니다. 반환값이 count
와 다를 경우, 파일 쓰기에 문제가 발생했음을 의미합니다.
간단한 예제: 정수 배열 저장
#include <stdio.h>
int main() {
FILE *fp;
int data[] = {10, 20, 30, 40, 50};
// 바이너리 쓰기 모드로 파일 열기
fp = fopen("output.bin", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// fwrite를 사용하여 배열 저장
size_t result = fwrite(data, sizeof(int), 5, fp);
if (result != 5) {
perror("파일 쓰기 실패");
}
// 파일 닫기
fclose(fp);
return 0;
}
복합 데이터(구조체) 저장
구조체 데이터를 파일에 저장하는 경우, 데이터의 크기와 순서가 중요합니다.
#include <stdio.h>
typedef struct {
char name[20];
int age;
float score;
} Student;
int main() {
FILE *fp;
Student student = {"Alice", 21, 95.5};
fp = fopen("student.bin", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
fwrite(&student, sizeof(Student), 1, fp);
fclose(fp);
return 0;
}
주의 사항
- 데이터의 크기와 순서는 파일을 읽을 때도 동일해야 합니다.
- 구조체 데이터를 저장할 때는 멤버 정렬(Padding) 때문에 예상 크기와 실제 크기가 다를 수 있으므로 주의해야 합니다.
fwrite
를 활용하면 바이너리 데이터 저장이 쉽고 효율적입니다. 적절한 크기와 포맷을 관리하여 데이터를 올바르게 저장해야 합니다.
fread를 이용한 바이너리 데이터 읽기
fread
함수는 파일에서 바이너리 데이터를 읽어 프로그램으로 가져오는 데 사용됩니다. 이 함수는 배열, 구조체, 또는 기타 복합 데이터를 효율적으로 읽어올 수 있습니다.
fread 함수의 문법
fread
함수의 기본 문법은 다음과 같습니다:
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
- ptr: 읽어온 데이터를 저장할 버퍼의 시작 주소를 가리킵니다.
- size: 읽을 데이터의 단위 크기(바이트)를 지정합니다.
- count: 읽을 데이터 단위의 개수를 지정합니다.
- stream: 데이터를 읽을 파일 포인터를 지정합니다.
fread의 반환값
fread
는 성공적으로 읽은 데이터 단위의 개수를 반환합니다. 반환값이 count
보다 작으면 파일 끝에 도달했거나 읽기 오류가 발생했음을 의미합니다.
간단한 예제: 정수 배열 읽기
#include <stdio.h>
int main() {
FILE *fp;
int data[5] = {0};
// 바이너리 읽기 모드로 파일 열기
fp = fopen("output.bin", "rb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// fread를 사용하여 배열 읽기
size_t result = fread(data, sizeof(int), 5, fp);
if (result != 5) {
perror("파일 읽기 실패");
} else {
for (int i = 0; i < 5; i++) {
printf("data[%d] = %d\n", i, data[i]);
}
}
// 파일 닫기
fclose(fp);
return 0;
}
복합 데이터(구조체) 읽기
#include <stdio.h>
typedef struct {
char name[20];
int age;
float score;
} Student;
int main() {
FILE *fp;
Student student;
// 바이너리 읽기 모드로 파일 열기
fp = fopen("student.bin", "rb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// 구조체 읽기
fread(&student, sizeof(Student), 1, fp);
printf("Name: %s\n", student.name);
printf("Age: %d\n", student.age);
printf("Score: %.2f\n", student.score);
fclose(fp);
return 0;
}
파일 끝(EOF) 및 에러 처리
feof(FILE *stream)
: 파일 끝에 도달했는지 확인ferror(FILE *stream)
: 파일 읽기 중 오류가 발생했는지 확인
if (feof(fp)) {
printf("파일 끝에 도달했습니다.\n");
}
if (ferror(fp)) {
printf("파일 읽기 중 오류가 발생했습니다.\n");
}
주의 사항
- 읽어올 데이터의 크기와 순서는 저장 시와 일치해야 합니다.
- 읽기 작업 후 반드시 에러를 확인하여 데이터 손실을 방지해야 합니다.
fread
를 사용하면 저장된 바이너리 데이터를 손쉽게 불러올 수 있으며, 이를 통해 다양한 데이터 처리가 가능합니다.
구조체의 바이너리 입출력
구조체는 여러 데이터 필드를 하나로 묶어 관리할 수 있는 데이터 타입으로, 바이너리 입출력 작업에서도 자주 사용됩니다. fwrite
와 fread
를 활용하면 구조체 데이터를 효율적으로 파일에 저장하고 읽어올 수 있습니다.
구조체 바이너리 저장
구조체 데이터를 파일에 저장할 때, 각 필드가 순서대로 바이너리 형식으로 저장됩니다.
#include <stdio.h>
typedef struct {
char name[20];
int age;
float salary;
} Employee;
int main() {
FILE *fp;
Employee emp = {"John Doe", 30, 75000.50};
// 바이너리 쓰기 모드로 파일 열기
fp = fopen("employee.bin", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// 구조체 저장
fwrite(&emp, sizeof(Employee), 1, fp);
// 파일 닫기
fclose(fp);
return 0;
}
구조체 바이너리 읽기
파일에서 저장된 구조체 데이터를 읽어오는 과정입니다. 저장 시 사용한 구조체와 동일한 구조체 정의가 필요합니다.
#include <stdio.h>
typedef struct {
char name[20];
int age;
float salary;
} Employee;
int main() {
FILE *fp;
Employee emp;
// 바이너리 읽기 모드로 파일 열기
fp = fopen("employee.bin", "rb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// 구조체 읽기
fread(&emp, sizeof(Employee), 1, fp);
// 읽은 데이터 출력
printf("Name: %s\n", emp.name);
printf("Age: %d\n", emp.age);
printf("Salary: %.2f\n", emp.salary);
// 파일 닫기
fclose(fp);
return 0;
}
여러 구조체 저장 및 읽기
구조체 배열을 사용하면 여러 개의 구조체 데이터를 연속적으로 저장하고 읽을 수 있습니다.
#include <stdio.h>
typedef struct {
char name[20];
int age;
float salary;
} Employee;
int main() {
FILE *fp;
Employee employees[3] = {
{"Alice", 25, 50000.00},
{"Bob", 28, 60000.00},
{"Charlie", 35, 70000.00}
};
// 구조체 배열 저장
fp = fopen("employees.bin", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
fwrite(employees, sizeof(Employee), 3, fp);
fclose(fp);
// 구조체 배열 읽기
Employee loadedEmployees[3];
fp = fopen("employees.bin", "rb");
fread(loadedEmployees, sizeof(Employee), 3, fp);
fclose(fp);
// 데이터 출력
for (int i = 0; i < 3; i++) {
printf("Name: %s, Age: %d, Salary: %.2f\n",
loadedEmployees[i].name, loadedEmployees[i].age, loadedEmployees[i].salary);
}
return 0;
}
주의 사항
- 멤버 정렬(Padding)
구조체 멤버 간의 정렬로 인해 예상 크기와 실제 크기가 다를 수 있습니다. 이를 방지하려면#pragma pack
을 사용하거나, 데이터 교환 시 직렬화를 고려해야 합니다. - 플랫폼 간 호환성
구조체 데이터를 파일로 저장할 때, 다른 시스템에서 읽을 경우 데이터 크기와 엔디언 차이로 문제가 발생할 수 있습니다.
구조체를 바이너리 파일로 입출력하면 데이터의 저장 및 복원 작업이 간편해집니다. 이를 통해 효율적인 데이터 관리와 처리 작업이 가능해집니다.
에러 처리와 파일 닫기
파일 작업 중 발생할 수 있는 다양한 에러를 적절히 처리하고, 작업이 완료된 후에는 반드시 파일을 닫아야 합니다. 이는 데이터 손실 방지와 자원 누수를 막기 위해 중요합니다.
에러 처리 방법
- 파일 열기 에러 확인
파일을 열 때fopen
이NULL
을 반환하면 파일 열기에 실패한 것입니다. 이를 확인하고 적절히 처리해야 합니다.
FILE *fp = fopen("example.bin", "rb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
- 읽기/쓰기 에러 확인
- 쓰기 에러 확인:
fwrite
함수의 반환값이 쓰려는 데이터 개수보다 작으면 오류가 발생한 것입니다. - 읽기 에러 확인:
fread
함수의 반환값이 읽으려는 데이터 개수보다 작으면 오류가 발생했거나 파일 끝에 도달한 것입니다.
size_t result = fwrite(data, sizeof(int), 5, fp);
if (result != 5) {
perror("파일 쓰기 실패");
}
result = fread(data, sizeof(int), 5, fp);
if (result != 5) {
if (feof(fp)) {
printf("파일 끝에 도달했습니다.\n");
} else {
perror("파일 읽기 실패");
}
}
- 파일 상태 확인 함수
feof(FILE *stream)
: 파일 끝에 도달했는지 확인합니다.ferror(FILE *stream)
: 파일 작업 중 오류가 발생했는지 확인합니다.
if (feof(fp)) {
printf("파일 끝에 도달했습니다.\n");
}
if (ferror(fp)) {
printf("파일 작업 중 오류가 발생했습니다.\n");
}
파일 닫기
파일 작업이 끝난 후에는 반드시 fclose
를 호출하여 파일을 닫아야 합니다. 이는 파일 작업 중 사용된 시스템 자원을 해제하는 데 필수적입니다.
fclose(fp);
파일을 닫지 않으면 다음과 같은 문제가 발생할 수 있습니다:
- 데이터 손실 또는 손상
- 시스템 리소스 누수
- 다른 프로그램이 파일에 접근하지 못함
전체적인 에러 처리와 파일 닫기 예제
#include <stdio.h>
int main() {
FILE *fp;
int data[] = {1, 2, 3, 4, 5};
// 파일 열기
fp = fopen("data.bin", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// 데이터 쓰기
if (fwrite(data, sizeof(int), 5, fp) != 5) {
perror("파일 쓰기 실패");
fclose(fp); // 파일 닫기
return 1;
}
// 파일 닫기
if (fclose(fp) != 0) {
perror("파일 닫기 실패");
return 1;
}
printf("파일 작업이 성공적으로 완료되었습니다.\n");
return 0;
}
주의 사항
- 에러 처리는 모든 파일 작업에 포함되어야 합니다.
fclose
는 파일 포인터가NULL
이 아니더라도 호출되도록 해야 합니다.- 파일 작업 중 문제가 발생하면 작업을 중단하고 적절한 복구 절차를 수행해야 합니다.
이처럼 에러 처리와 파일 닫기는 안전하고 신뢰성 있는 파일 작업의 기본 요소입니다.
응용: 이미지 데이터 처리
이미지 파일은 일반적으로 바이너리 데이터로 저장되며, 이를 처리하려면 파일 포인터를 사용해 읽고 쓸 수 있습니다. 여기서는 BMP 파일의 헤더를 읽고 픽셀 데이터를 조작하는 간단한 예를 통해 바이너리 데이터 처리를 응용해 보겠습니다.
BMP 파일의 구조
BMP 파일은 크게 파일 헤더, 정보 헤더, 픽셀 데이터로 구성됩니다.
- 파일 헤더: 파일의 기본 정보를 담고 있습니다(파일 크기, 데이터 오프셋 등).
- 정보 헤더: 이미지의 속성 정보(너비, 높이, 색상 비트 등)를 포함합니다.
- 픽셀 데이터: 이미지의 실제 픽셀 값을 포함하는 바이너리 데이터입니다.
BMP 파일에서 헤더 읽기
다음은 BMP 파일의 파일 헤더와 정보 헤더를 읽는 예제입니다.
#include <stdio.h>
#include <stdint.h>
#pragma pack(push, 1) // 구조체 패딩 제거
typedef struct {
uint16_t bfType; // 파일 식별(일반적으로 'BM')
uint32_t bfSize; // 파일 크기
uint16_t bfReserved1; // 예약 필드
uint16_t bfReserved2; // 예약 필드
uint32_t bfOffBits; // 픽셀 데이터 오프셋
} BMPFileHeader;
typedef struct {
uint32_t biSize; // 정보 헤더 크기
int32_t biWidth; // 이미지 너비
int32_t biHeight; // 이미지 높이
uint16_t biPlanes; // 색상 평면 수(항상 1)
uint16_t biBitCount; // 픽셀당 비트 수
uint32_t biCompression; // 압축 방식
uint32_t biSizeImage; // 이미지 데이터 크기
int32_t biXPelsPerMeter; // 수평 해상도
int32_t biYPelsPerMeter; // 수직 해상도
uint32_t biClrUsed; // 색상 테이블 사용 수
uint32_t biClrImportant; // 중요한 색상 수
} BMPInfoHeader;
#pragma pack(pop)
int main() {
FILE *fp = fopen("example.bmp", "rb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
// 파일 헤더 읽기
fread(&fileHeader, sizeof(BMPFileHeader), 1, fp);
// 파일 타입 확인
if (fileHeader.bfType != 0x4D42) { // 'BM'에 해당
printf("BMP 파일이 아닙니다.\n");
fclose(fp);
return 1;
}
// 정보 헤더 읽기
fread(&infoHeader, sizeof(BMPInfoHeader), 1, fp);
printf("이미지 크기: %dx%d\n", infoHeader.biWidth, infoHeader.biHeight);
printf("픽셀당 비트 수: %d\n", infoHeader.biBitCount);
fclose(fp);
return 0;
}
픽셀 데이터 조작
BMP 파일의 픽셀 데이터를 조작하려면 데이터 오프셋을 계산한 뒤 파일을 읽고 쓰는 작업을 수행합니다. 예를 들어, 흑백 필터를 적용하려면 픽셀 값을 평균으로 변환할 수 있습니다.
#include <stdio.h>
void applyGrayscale(uint8_t *pixelData, size_t dataSize, int bitCount) {
for (size_t i = 0; i < dataSize; i += 3) { // RGB는 3바이트
uint8_t gray = (pixelData[i] + pixelData[i + 1] + pixelData[i + 2]) / 3;
pixelData[i] = pixelData[i + 1] = pixelData[i + 2] = gray;
}
}
주의 사항
- 픽셀 데이터 오프셋 확인: BMP 헤더에서
bfOffBits
를 참조하여 픽셀 데이터의 시작 위치를 확인해야 합니다. - 비트 깊이: BMP 파일의 비트 깊이(24비트, 32비트 등)에 따라 픽셀 데이터의 처리 방식이 달라집니다.
- 파일 크기 관리: 파일 크기와 데이터 크기가 일치하는지 확인해야 데이터 손상을 방지할 수 있습니다.
응용 사례
- 간단한 이미지 필터 작성(흑백, 반전 등)
- 이미지 크기 변경(축소/확대)
- 픽셀 데이터를 분석하여 이미지의 주요 특징 추출
이러한 방법을 통해 BMP와 같은 이미지 파일의 데이터를 효율적으로 처리할 수 있습니다.
연습 문제와 해설
바이너리 파일 입출력과 파일 포인터를 활용한 이해를 돕기 위해 몇 가지 연습 문제와 해설을 제공합니다. 이를 통해 실제로 코드를 작성하며 개념을 체득할 수 있습니다.
문제 1: 정수 배열 저장 및 읽기
정수 배열 {10, 20, 30, 40, 50}
을 바이너리 파일에 저장한 뒤, 다시 읽어와 출력하는 프로그램을 작성하세요.
- 파일 이름:
numbers.bin
- 저장:
fwrite
사용 - 읽기:
fread
사용
해설:
정수 배열을 저장할 때 데이터 크기와 배열 길이를 지정하여 fwrite
로 파일에 쓰고, fread
로 읽어와 출력합니다.
#include <stdio.h>
int main() {
FILE *fp;
int numbers[] = {10, 20, 30, 40, 50};
int buffer[5];
// 파일 쓰기
fp = fopen("numbers.bin", "wb");
fwrite(numbers, sizeof(int), 5, fp);
fclose(fp);
// 파일 읽기
fp = fopen("numbers.bin", "rb");
fread(buffer, sizeof(int), 5, fp);
fclose(fp);
// 출력
for (int i = 0; i < 5; i++) {
printf("%d ", buffer[i]);
}
return 0;
}
문제 2: 구조체 데이터를 저장하고 읽기
다음 Student
구조체를 정의하고, 구조체 데이터를 파일에 저장한 뒤 읽어오는 프로그램을 작성하세요.
- 저장 데이터: 이름
"Alice"
, 나이21
, 학점3.8
- 파일 이름:
student.bin
typedef struct {
char name[20];
int age;
float gpa;
} Student;
해설:
구조체는 크기를 확인하여 fwrite
로 저장하고, 동일한 크기와 구조로 fread
를 통해 읽어옵니다.
#include <stdio.h>
typedef struct {
char name[20];
int age;
float gpa;
} Student;
int main() {
FILE *fp;
Student student = {"Alice", 21, 3.8};
Student buffer;
// 파일 쓰기
fp = fopen("student.bin", "wb");
fwrite(&student, sizeof(Student), 1, fp);
fclose(fp);
// 파일 읽기
fp = fopen("student.bin", "rb");
fread(&buffer, sizeof(Student), 1, fp);
fclose(fp);
// 출력
printf("Name: %s\n", buffer.name);
printf("Age: %d\n", buffer.age);
printf("GPA: %.2f\n", buffer.gpa);
return 0;
}
문제 3: 파일 작업 에러 처리
파일 작업 중 발생할 수 있는 에러를 처리하는 코드를 작성하세요.
- 파일을 열 수 없는 경우 에러 메시지 출력
- 데이터 쓰기 실패 시 에러 메시지 출력
해설:fopen
반환값이 NULL
인 경우 에러를 출력하고 종료하며, fwrite
와 fread
의 반환값을 확인하여 성공 여부를 판단합니다.
#include <stdio.h>
int main() {
FILE *fp;
int data[] = {1, 2, 3};
// 파일 열기
fp = fopen("data.bin", "wb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
// 데이터 쓰기
if (fwrite(data, sizeof(int), 3, fp) != 3) {
perror("파일 쓰기 실패");
fclose(fp);
return 1;
}
fclose(fp);
printf("파일 작업 완료.\n");
return 0;
}
문제 4: 이미지 데이터 처리
BMP 파일에서 파일 헤더를 읽고, 이미지의 너비와 높이를 출력하는 프로그램을 작성하세요.
해설:
파일 헤더의 구조를 정확히 정의하고, fread
를 통해 데이터를 읽어 필요한 정보를 출력합니다.
#include <stdio.h>
#include <stdint.h>
#pragma pack(push, 1)
typedef struct {
uint16_t bfType;
uint32_t bfSize;
uint16_t bfReserved1;
uint16_t bfReserved2;
uint32_t bfOffBits;
} BMPFileHeader;
typedef struct {
uint32_t biSize;
int32_t biWidth;
int32_t biHeight;
} BMPInfoHeader;
#pragma pack(pop)
int main() {
FILE *fp = fopen("example.bmp", "rb");
if (fp == NULL) {
perror("파일 열기 실패");
return 1;
}
BMPFileHeader fileHeader;
BMPInfoHeader infoHeader;
fread(&fileHeader, sizeof(BMPFileHeader), 1, fp);
fread(&infoHeader, sizeof(BMPInfoHeader), 1, fp);
printf("Width: %d\n", infoHeader.biWidth);
printf("Height: %d\n", infoHeader.biHeight);
fclose(fp);
return 0;
}
이 연습 문제들을 통해 파일 포인터와 바이너리 데이터를 다루는 다양한 시나리오를 연습할 수 있습니다.
요약
이번 기사에서는 C언어에서 파일 포인터를 사용하여 바이너리 데이터를 저장하고 읽는 방법을 다뤘습니다. fopen
, fwrite
, fread
와 같은 핵심 함수의 사용법을 설명하고, 구조체 데이터 처리 및 에러 처리 방법을 소개했습니다. 또한, 이미지 파일 데이터의 응용 예시와 연습 문제를 통해 실무적인 이해를 돕는 기회를 제공했습니다. 파일 작업에서의 안전성과 효율성을 높이기 위한 원칙을 배웠습니다.