C 언어에서 파일 입출력은 프로그래밍에서 데이터를 영구적으로 저장하고 처리하는 데 핵심적인 역할을 합니다. 특히, fprintf
와 fscanf
함수는 형식화된 데이터를 파일에 쓰고 읽는 데 사용됩니다. 이러한 함수의 사용법을 익히면 효율적인 데이터 처리가 가능하며, 프로그램의 안정성과 유지보수성을 높일 수 있습니다. 본 기사에서는 fprintf
와 fscanf
의 기본 사용법부터 응용 사례, 문제 해결 방안까지 다양한 관점을 다룰 예정입니다.
fprintf와 fscanf의 개념 및 기본 사용법
fprintf
와 fscanf
는 C 언어에서 파일 입출력을 처리하기 위해 제공되는 표준 함수입니다.
fprintf의 정의와 기본 사용법
fprintf
는 지정된 파일 스트림에 형식화된 데이터를 출력하는 함수입니다. 다음은 기본적인 함수 시그니처입니다:
int fprintf(FILE *stream, const char *format, ...);
stream
: 데이터를 출력할 파일 포인터입니다.format
: 출력 형식을 지정하는 문자열입니다.- 가변 인수(
...
): 포맷에 따라 출력할 데이터입니다.
사용 예제:
FILE *file = fopen("example.txt", "w");
if (file) {
fprintf(file, "Name: %s, Age: %d\n", "Alice", 30);
fclose(file);
}
fscanf의 정의와 기본 사용법
fscanf
는 지정된 파일 스트림에서 데이터를 읽고, 형식화된 입력 처리를 수행하는 함수입니다. 기본 시그니처는 다음과 같습니다:
int fscanf(FILE *stream, const char *format, ...);
stream
: 데이터를 읽을 파일 포인터입니다.format
: 입력 형식을 지정하는 문자열입니다.- 가변 인수(
...
): 데이터를 저장할 변수들의 주소입니다.
사용 예제:
FILE *file = fopen("example.txt", "r");
if (file) {
char name[50];
int age;
fscanf(file, "Name: %s, Age: %d", name, &age);
printf("Read - Name: %s, Age: %d\n", name, age);
fclose(file);
}
기본 개념 요약
fprintf
: 파일에 데이터를 포맷화하여 출력.fscanf
: 파일에서 포맷화된 데이터를 읽기.
이 두 함수는 파일 입출력에서 데이터 구조화를 간단하게 처리하는 데 매우 유용합니다.
fprintf로 파일에 데이터 쓰기
fprintf
함수는 파일에 데이터를 형식화하여 출력하는 데 사용됩니다. 이 함수는 포맷 문자열을 이용해 데이터를 원하는 형식으로 표현할 수 있으며, 가변 길이의 데이터를 처리하는 데 매우 유용합니다.
기본 사용법
다음은 fprintf
로 파일에 데이터를 쓰는 기본 예제입니다:
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "w"); // 파일 쓰기 모드로 열기
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
// 데이터를 형식화하여 파일에 출력
fprintf(file, "Name: %s\n", "John Doe");
fprintf(file, "Age: %d\n", 28);
fprintf(file, "Height: %.2f cm\n", 175.5);
fclose(file); // 파일 닫기
return 0;
}
출력 결과:data.txt
파일의 내용은 다음과 같습니다:
Name: John Doe
Age: 28
Height: 175.50 cm
포맷 문자열의 유연성
- 문자열 출력:
%s
를 사용하여 문자열 데이터를 출력합니다. - 정수 출력:
%d
,%u
등을 사용해 정수형 데이터를 출력합니다. - 소수 출력:
%f
,%.2f
등을 사용해 부동소수점 데이터를 출력하며, 소수점 자릿수를 지정할 수 있습니다. - 16진수/8진수 출력:
%x
,%o
를 사용해 16진수 또는 8진수로 출력할 수 있습니다.
응용 사례
- 구조체 데이터 출력
구조체를fprintf
로 출력하여 데이터를 정리할 수 있습니다.
typedef struct {
char name[50];
int age;
float height;
} Person;
void savePersonToFile(FILE *file, Person p) {
fprintf(file, "Name: %s, Age: %d, Height: %.2f\n", p.name, p.age, p.height);
}
- 로그 파일 생성
프로그램 실행 중 상태를 기록하는 로그 파일 작성에 활용할 수 있습니다.
FILE *logFile = fopen("log.txt", "a"); // 추가 모드로 열기
fprintf(logFile, "[%s] Error: %s\n", "2024-12-25 10:00:00", "파일 없음");
fclose(logFile);
주의 사항
- 파일이 제대로 열렸는지 확인해야 합니다.
fopen
이 실패하면 NULL을 반환합니다. - 데이터를 쓰고 나서는 반드시
fclose
를 호출하여 리소스를 해제해야 합니다. - 포맷 문자열을 안전하게 작성하여 보안 문제를 방지해야 합니다.
fprintf
는 데이터를 형식화하여 저장하는 강력한 도구로, 구조적 데이터 관리와 로깅 등에 필수적으로 사용됩니다.
fscanf로 파일에서 데이터 읽기
fscanf
함수는 파일에서 데이터를 읽어 들이고 이를 형식화하여 변수에 저장하는 데 사용됩니다. 이 함수는 데이터를 구조적으로 처리하거나 분석할 때 유용합니다.
기본 사용법
다음은 fscanf
를 사용하여 파일에서 데이터를 읽는 간단한 예제입니다:
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r"); // 파일 읽기 모드로 열기
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
char name[50];
int age;
float height;
// 데이터를 파일에서 읽기
fscanf(file, "Name: %s\n", name);
fscanf(file, "Age: %d\n", &age);
fscanf(file, "Height: %f\n", &height);
printf("Name: %s, Age: %d, Height: %.2f cm\n", name, age, height);
fclose(file); // 파일 닫기
return 0;
}
data.txt
의 내용이 다음과 같다면:
Name: John
Age: 28
Height: 175.50
출력 결과:
Name: John, Age: 28, Height: 175.50 cm
포맷 문자열과 가변 인수
fscanf
는 포맷 문자열을 사용하여 파일의 데이터를 원하는 변수에 저장합니다.
- 문자열 입력:
%s
를 사용해 문자열 데이터를 읽습니다. - 정수 입력:
%d
를 사용해 정수형 데이터를 읽습니다. - 소수 입력:
%f
를 사용해 부동소수점 데이터를 읽습니다.
응용 사례
- 구조체 데이터 읽기
파일의 데이터를 구조체에 저장하는 예제:
typedef struct {
char name[50];
int age;
float height;
} Person;
Person readPersonFromFile(FILE *file) {
Person p;
fscanf(file, "Name: %s, Age: %d, Height: %f", p.name, &p.age, &p.height);
return p;
}
- 다양한 데이터 유형 읽기
여러 유형의 데이터를 처리하는 복합 예제:
FILE *file = fopen("data.txt", "r");
if (file) {
char category[20];
int id;
double price;
fscanf(file, "Category: %s ID: %d Price: %lf", category, &id, &price);
printf("Category: %s, ID: %d, Price: %.2f\n", category, id, price);
fclose(file);
}
주의 사항
- 읽기 전에 파일 포인터가 제대로 열렸는지 확인하세요.
- 데이터 형식이 파일 내용과 일치하지 않으면 예상치 못한 동작이 발생할 수 있습니다.
- 공백, 줄 바꿈 등의 구문 요소는 포맷 문자열과 일치해야 합니다.
- 포맷 문자열에서
%s
를 사용할 경우 버퍼 오버플로를 방지하기 위해 길이를 제한하는 것이 좋습니다.
예:%49s
(최대 49자 읽기).
오류 처리
fscanf
는 읽은 항목 수를 반환합니다. 이를 활용해 오류를 처리할 수 있습니다.
int result = fscanf(file, "%s %d", name, &age);
if (result != 2) {
printf("읽기 오류 발생\n");
}
fscanf
는 파일에서 데이터를 효율적으로 읽고 이를 변수에 할당하는 데 유용하며, 파일 기반 데이터 처리의 핵심 도구입니다.
파일 입출력 오류 처리
파일 입출력 작업에서는 다양한 오류가 발생할 수 있습니다. fprintf
와 fscanf
를 사용할 때 이러한 오류를 효과적으로 처리하는 방법을 알아봅니다.
파일 열기 오류 처리
파일을 열지 못한 경우, fopen
함수는 NULL
을 반환합니다. 이를 확인하여 오류를 처리할 수 있습니다.
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("파일 열기 오류");
return 1; // 프로그램 종료
}
perror
함수는 표준 출력에 오류 메시지를 출력합니다.
fprintf 및 fscanf의 반환값 확인
fprintf
반환값: 출력된 문자의 개수를 반환합니다. 음수면 출력에 실패한 것입니다.
if (fprintf(file, "Name: %s\n", "John") < 0) {
perror("파일 쓰기 오류");
}
fscanf
반환값: 성공적으로 읽은 항목의 개수를 반환합니다. 읽기 실패 시 반환값이 예상치 못한 값이 됩니다.
int result = fscanf(file, "Name: %s Age: %d", name, &age);
if (result != 2) {
fprintf(stderr, "파일 읽기 오류: 읽은 항목 수 %d\n", result);
}
파일 쓰기 중단 처리
파일 쓰기 중 시스템의 리소스가 부족하거나 디스크가 가득 찬 경우 쓰기가 중단될 수 있습니다.
- 쓰기 확인 방법:
if (fflush(file) != 0) { // 파일 버퍼를 강제로 비움
perror("파일 버퍼 비우기 실패");
}
EOF(End of File) 처리
파일 끝에 도달했는지 확인하는 방법:
while (fscanf(file, "%s", buffer) != EOF) {
printf("읽은 데이터: %s\n", buffer);
}
EOF
는 파일의 끝을 나타내는 상수입니다.feof
함수로 파일 끝인지 확인할 수 있습니다:
if (feof(file)) {
printf("파일 끝에 도달했습니다.\n");
}
파일 상태 확인
파일 작업 중 상태를 확인하려면 다음 함수를 사용할 수 있습니다:
ferror
: 파일 작업 중 오류가 발생했는지 확인합니다.
if (ferror(file)) {
perror("파일 작업 중 오류 발생");
clearerr(file); // 오류 플래그를 재설정
}
feof
: 파일의 끝에 도달했는지 확인합니다.
if (feof(file)) {
printf("파일 끝에 도달했습니다.\n");
}
권장 오류 처리 패턴
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
char buffer[50];
while (fscanf(file, "%49s", buffer) != EOF) {
if (ferror(file)) {
perror("파일 읽기 오류");
break;
}
printf("읽은 데이터: %s\n", buffer);
}
fclose(file);
오류 처리의 중요성
- 프로그램의 안정성을 보장합니다.
- 예상치 못한 데이터 손실을 방지합니다.
- 사용자에게 적절한 오류 메시지를 제공하여 문제를 진단할 수 있도록 돕습니다.
파일 입출력 오류 처리는 견고하고 신뢰할 수 있는 프로그램을 작성하는 데 필수적입니다. 오류를 예측하고 처리하면 프로그램의 안정성을 크게 향상시킬 수 있습니다.
fprintf와 fscanf의 유용한 활용법
fprintf
와 fscanf
는 파일 입출력의 기본을 제공할 뿐만 아니라 다양한 응용 사례에서 데이터를 효율적으로 처리할 수 있는 도구입니다. 이 섹션에서는 실제 프로그래밍에서 이 함수들을 활용하는 방법을 살펴봅니다.
데이터 구조 저장 및 로드
데이터 구조를 파일에 저장하고 다시 읽어오는 작업은 데이터 처리 프로그램에서 흔히 사용됩니다.
#include <stdio.h>
typedef struct {
char name[50];
int age;
float height;
} Person;
void savePersonToFile(FILE *file, Person p) {
fprintf(file, "%s %d %.2f\n", p.name, p.age, p.height);
}
Person loadPersonFromFile(FILE *file) {
Person p;
fscanf(file, "%s %d %f", p.name, &p.age, &p.height);
return p;
}
int main() {
Person p1 = {"Alice", 25, 170.5};
FILE *file = fopen("person.txt", "w");
if (file) {
savePersonToFile(file, p1);
fclose(file);
}
file = fopen("person.txt", "r");
if (file) {
Person p2 = loadPersonFromFile(file);
printf("Name: %s, Age: %d, Height: %.2f\n", p2.name, p2.age, p2.height);
fclose(file);
}
return 0;
}
로그 파일 생성
프로그램의 실행 상태를 기록하여 디버깅하거나 기록 보관용으로 사용할 수 있습니다.
#include <stdio.h>
#include <time.h>
void writeLog(FILE *logFile, const char *message) {
time_t now = time(NULL);
fprintf(logFile, "[%s] %s\n", ctime(&now), message);
}
int main() {
FILE *logFile = fopen("log.txt", "a");
if (logFile) {
writeLog(logFile, "프로그램 시작");
writeLog(logFile, "작업 완료");
fclose(logFile);
}
return 0;
}
데이터 분석 및 처리
파일로부터 데이터를 읽어와 분석하는 데 fscanf
를 사용할 수 있습니다.
#include <stdio.h>
int main() {
FILE *file = fopen("data.txt", "r");
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
int sum = 0, count = 0, value;
while (fscanf(file, "%d", &value) != EOF) {
sum += value;
count++;
}
fclose(file);
printf("합계: %d, 평균: %.2f\n", sum, (float)sum / count);
return 0;
}
다중 데이터 유형 처리
파일에 서로 다른 데이터 유형을 저장하고 다시 읽어오는 예제입니다.
#include <stdio.h>
int main() {
FILE *file = fopen("mixed_data.txt", "w");
if (file) {
fprintf(file, "%s %d %.2f\n", "Item1", 100, 12.5);
fprintf(file, "%s %d %.2f\n", "Item2", 200, 8.99);
fclose(file);
}
file = fopen("mixed_data.txt", "r");
if (file) {
char name[50];
int quantity;
float price;
while (fscanf(file, "%s %d %f", name, &quantity, &price) != EOF) {
printf("Name: %s, Quantity: %d, Price: %.2f\n", name, quantity, price);
}
fclose(file);
}
return 0;
}
유용한 팁
- 데이터를 구조화하기 위해 파일 포맷을 설계합니다. 예: CSV, JSON, XML.
fprintf
와fscanf
를 활용해 간단한 파일 기반 데이터베이스를 구현할 수 있습니다.- 데이터 읽기/쓰기 작업을 캡슐화하여 코드 가독성을 높이고 재사용성을 증대시킵니다.
fprintf
와 fscanf
는 간단하면서도 강력한 도구로, 데이터를 처리하고 저장하는 작업을 체계적이고 효율적으로 수행할 수 있습니다. 이러한 함수들을 적절히 활용하면 프로그램의 기능을 확장할 수 있습니다.
포맷 문자열의 사용 주의점
fprintf
와 fscanf
에서 포맷 문자열은 데이터를 출력하거나 입력 형식을 지정하는 핵심 요소입니다. 하지만 잘못된 포맷 문자열 사용은 예상치 못한 오류나 심각한 보안 문제를 초래할 수 있습니다. 안전하고 효과적으로 포맷 문자열을 사용하는 방법과 주의사항을 알아봅니다.
포맷 문자열의 주요 구성 요소
포맷 문자열은 다음과 같은 형식 지정자를 포함합니다:
%d
,%i
: 정수%f
,%.2f
: 부동소수점 수%s
: 문자열%c
: 문자%x
,%o
: 16진수, 8진수%p
: 포인터 주소
주의 사항 및 안전한 사용법
1. 입력 데이터 크기 제한
%s
형식 지정자는 문자열 입력에서 버퍼 오버플로를 초래할 수 있습니다. 이를 방지하려면 최대 길이를 지정하세요.
char buffer[50];
fscanf(file, "%49s", buffer); // 최대 49자까지만 읽음
이렇게 하면 메모리 초과 접근으로 인한 프로그램 충돌을 방지할 수 있습니다.
2. 출력 포맷의 명확한 정의
포맷 문자열에서 출력의 형태를 명확히 지정해야 합니다.
fprintf(file, "Value: %.2f\n", 123.4567); // 소수점 이하 2자리만 출력
부정확하거나 불완전한 포맷 정의는 예상치 못한 출력 결과를 초래할 수 있습니다.
3. 포맷 문자열에 외부 입력 사용 금지
외부 입력을 포맷 문자열로 직접 사용하는 것은 보안 취약점(포맷 문자열 공격)을 초래할 수 있습니다.
// 잘못된 예
fprintf(file, user_input); // user_input에 "%s %s"가 포함되면 예상치 못한 동작 발생
대신, 포맷 문자열을 명확히 정의하세요.
fprintf(file, "%s", user_input); // 안전한 사용법
4. 데이터 타입 일치 확인
포맷 지정자와 데이터 타입이 일치하지 않으면 런타임 오류가 발생할 수 있습니다.
int value = 123;
fprintf(file, "%f", value); // 잘못된 예
정확한 데이터 타입에 맞는 형식 지정자를 사용하세요.
fprintf(file, "%d", value); // 올바른 예
포맷 문자열의 고급 사용
1. 동적 폭 및 정밀도 설정
포맷 문자열에서 폭이나 정밀도를 동적으로 지정할 수 있습니다.
int width = 10;
fprintf(file, "%*d\n", width, 42); // 폭 10으로 정수 출력
2. 사용자 정의 포맷 생성
데이터 구조의 특정 형식을 포맷 문자열로 정의할 수 있습니다.
typedef struct {
char name[50];
int age;
} Person;
void savePerson(FILE *file, Person p) {
fprintf(file, "Name: %s, Age: %d\n", p.name, p.age);
}
포맷 문자열 오류 방지 팁
- 포맷 문자열을 정적 또는 하드코딩된 값으로 유지하세요.
- 가변 인수와 포맷 문자열의 매칭을 검증하세요.
- 컴파일러 경고(
-Wall
,-Wformat-security
등)를 활성화하여 포맷 문자열 관련 오류를 감지하세요.
요약
포맷 문자열은 파일 입출력에서 데이터를 구조화하고 표현하는 강력한 도구입니다. 하지만 부주의한 사용은 프로그램 오류나 보안 취약점을 초래할 수 있으므로, 포맷 문자열의 작성과 사용 시 안전성을 항상 고려해야 합니다. 적절한 방식을 활용하면 fprintf
와 fscanf
의 기능을 최대한 활용할 수 있습니다.
대안 입출력 함수 비교
C 언어에서는 fprintf
와 fscanf
외에도 다양한 입출력 함수를 제공하여 특정 상황에 더 적합한 방법을 선택할 수 있습니다. 이 섹션에서는 fgets
, fputs
와 같은 대안 함수들과 fprintf
, fscanf
를 비교하며, 각 함수의 특징과 적합한 용도를 설명합니다.
fprintf와 fscanf의 특징
- 장점
- 포맷 문자열을 사용해 데이터를 정밀하게 출력 및 입력할 수 있습니다.
- 여러 데이터 유형을 한 번에 처리할 수 있습니다.
- 단점
- 파일 포맷이 예상과 다를 경우 읽기 오류가 발생할 수 있습니다.
- 간단한 입출력 작업에서는 상대적으로 복잡할 수 있습니다.
fgets와 fputs
- fgets: 파일에서 문자열을 한 줄씩 읽습니다.
- fputs: 파일에 문자열을 한 줄씩 씁니다.
사용 예제:
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
fputs("Hello, World!\n", file); // 문자열 쓰기
fputs("C programming is fun.\n", file);
fclose(file);
}
file = fopen("example.txt", "r");
if (file) {
char buffer[100];
while (fgets(buffer, sizeof(buffer), file)) { // 한 줄 읽기
printf("%s", buffer);
}
fclose(file);
}
return 0;
}
비교
함수 | 장점 | 단점 |
---|---|---|
fprintf | 다양한 데이터 유형 처리 가능 | 포맷 문자열의 정확성이 필요함 |
fscanf | 포맷 문자열로 구조적 데이터 읽기 가능 | 데이터 포맷 불일치 시 오류 가능 |
fputs | 간단한 문자열 쓰기에 적합 | 포맷화된 데이터 출력 불가 |
fgets | 한 줄씩 데이터를 읽기에 편리 | 문자열 이외 데이터 처리 불가 |
getc와 putc
- getc: 파일에서 문자를 한 번에 한 개씩 읽습니다.
- putc: 파일에 문자를 한 번에 한 개씩 씁니다.
사용 예제:
#include <stdio.h>
int main() {
FILE *file = fopen("example.txt", "w");
if (file) {
putc('A', file); // 문자 쓰기
putc('B', file);
fclose(file);
}
file = fopen("example.txt", "r");
if (file) {
char ch;
while ((ch = getc(file)) != EOF) { // 문자 읽기
putchar(ch);
}
fclose(file);
}
return 0;
}
비교
함수 | 장점 | 단점 |
---|---|---|
putc | 단일 문자 쓰기에 적합 | 다량의 데이터 처리에는 비효율적 |
getc | 단일 문자 읽기에 적합 | 문자열 및 구조적 데이터 처리 불가 |
scanf와 printf
scanf
와 printf
는 표준 입출력에 사용되며, fscanf
와 fprintf
의 콘솔 버전이라고 할 수 있습니다.
scanf
: 표준 입력(stdin)에서 형식화된 데이터 읽기.printf
: 표준 출력(stdout)에 형식화된 데이터 쓰기.
어떤 함수를 선택해야 할까?
- 구조화된 데이터 처리:
fprintf
와fscanf
는 데이터의 구조적 처리와 파일 포맷이 중요한 경우에 적합합니다.
- 간단한 문자열 입출력:
fgets
와fputs
는 텍스트 기반 파일을 다룰 때 간단하고 직관적입니다.
- 단일 문자 처리:
getc
와putc
는 개별 문자 처리나 바이너리 데이터 처리에 유용합니다.
- 콘솔 입출력:
scanf
와printf
는 파일이 아닌 콘솔 입출력 작업에 적합합니다.
각 함수는 목적에 따라 효율적으로 활용할 수 있으며, 프로그램의 요구사항에 따라 적절히 조합하여 사용하면 입출력 작업을 더 쉽게 처리할 수 있습니다.
연습 문제 및 코드 예제
fprintf
와 fscanf
를 활용한 파일 입출력의 이해를 돕기 위해 연습 문제와 예제를 제공합니다. 이 문제들은 실전에서 자주 접할 수 있는 데이터 처리 시나리오를 포함하고 있습니다.
문제 1: 학생 정보 저장 및 읽기
요구사항:
- 사용자로부터 학생의 이름, 나이, 성적을 입력받아 파일에 저장합니다.
- 파일에 저장된 데이터를 다시 읽어와 화면에 출력합니다.
코드 예제:
#include <stdio.h>
typedef struct {
char name[50];
int age;
float grade;
} Student;
void saveStudentToFile(FILE *file, Student s) {
fprintf(file, "%s %d %.2f\n", s.name, s.age, s.grade);
}
void loadStudentsFromFile(FILE *file) {
Student s;
while (fscanf(file, "%49s %d %f", s.name, &s.age, &s.grade) != EOF) {
printf("Name: %s, Age: %d, Grade: %.2f\n", s.name, s.age, s.grade);
}
}
int main() {
FILE *file = fopen("students.txt", "w");
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
Student s1 = {"Alice", 20, 85.5};
Student s2 = {"Bob", 22, 90.0};
saveStudentToFile(file, s1);
saveStudentToFile(file, s2);
fclose(file);
file = fopen("students.txt", "r");
if (file) {
loadStudentsFromFile(file);
fclose(file);
}
return 0;
}
문제 2: 판매 데이터 분석
요구사항:
- 판매 데이터가 파일에 저장되어 있습니다. 각 줄에는 상품명, 판매 수량, 가격이 기록됩니다.
- 데이터를 읽어 총 판매 금액을 계산하고 출력합니다.
코드 예제:
#include <stdio.h>
int main() {
FILE *file = fopen("sales.txt", "r");
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
char itemName[50];
int quantity;
float price, total = 0.0;
printf("Sales Data:\n");
printf("----------------------------\n");
printf("Item\tQuantity\tPrice\tTotal\n");
while (fscanf(file, "%49s %d %f", itemName, &quantity, &price) != EOF) {
float itemTotal = quantity * price;
total += itemTotal;
printf("%s\t%d\t\t%.2f\t%.2f\n", itemName, quantity, price, itemTotal);
}
fclose(file);
printf("----------------------------\n");
printf("Total Sales: %.2f\n", total);
return 0;
}
문제 3: 텍스트 데이터 수정
요구사항:
- 텍스트 파일에서 특정 단어를 찾아 다른 단어로 바꿉니다.
- 수정된 데이터를 새 파일에 저장합니다.
코드 예제:
#include <stdio.h>
#include <string.h>
int main() {
FILE *inputFile = fopen("input.txt", "r");
FILE *outputFile = fopen("output.txt", "w");
if (inputFile == NULL || outputFile == NULL) {
perror("파일 열기 오류");
return 1;
}
char word[50];
while (fscanf(inputFile, "%49s", word) != EOF) {
if (strcmp(word, "oldWord") == 0) {
fprintf(outputFile, "%s ", "newWord");
} else {
fprintf(outputFile, "%s ", word);
}
}
fclose(inputFile);
fclose(outputFile);
printf("단어 치환 작업이 완료되었습니다.\n");
return 0;
}
문제 4: CSV 파일 처리
요구사항:
- CSV 파일을 읽어 데이터를 분석합니다.
- 각 행의 값을 더하고 결과를 출력합니다.
코드 예제:
#include <stdio.h>
int main() {
FILE *file = fopen("data.csv", "r");
if (file == NULL) {
perror("파일 열기 오류");
return 1;
}
char line[100];
while (fgets(line, sizeof(line), file)) {
int sum = 0, value;
char *token = strtok(line, ",");
while (token) {
sscanf(token, "%d", &value);
sum += value;
token = strtok(NULL, ",");
}
printf("Row Sum: %d\n", sum);
}
fclose(file);
return 0;
}
연습 문제를 통해 배울 점
- 파일 입출력의 기본 흐름(열기, 읽기/쓰기, 닫기).
fprintf
와fscanf
를 활용한 구조적 데이터 처리.- 다양한 데이터 형식(텍스트, CSV 등)을 다루는 방법.
- 간단한 데이터 분석과 파일 수정 작업.
위 연습 문제들을 해결하면 파일 입출력과 데이터 처리 능력을 강화할 수 있습니다.
요약
본 기사에서는 C 언어에서 fprintf
와 fscanf
를 활용한 형식화된 입출력 처리의 기본 개념, 사용법, 응용 사례를 다뤘습니다. 주요 내용으로는 데이터 저장 및 읽기, 포맷 문자열의 안전한 사용, 파일 입출력 오류 처리, 대안 함수 비교, 실전 예제 등을 포함했습니다. 이를 통해 파일 기반 데이터 처리와 분석에서의 효율성을 높이는 방법을 이해할 수 있습니다.