기본 콘텐츠로 건너뛰기

방송대 C프로그래밍 13강: 파일 스트림과 랜덤 접근

0-썸네일-요약노트-C프로그래밍-13강

방송대 C프로그래밍 13강: 파일 스트림과 랜덤 접근

같은 파일이라도 "r"로 열면 보호되지만 "w"로 열면 기존 내용이 사라질 수 있다. 파일 처리는 함수 이름을 외우는 일이 아니라, 열기 전 상태와 사용할 자료 단위, 현재 위치, 실패 가능성을 차례로 판단하는 과정이다. 텍스트를 순서대로 기록하는 흐름과 고정 길이 레코드를 곧바로 찾는 흐름을 하나의 스트림 생애로 추적해 보자.

파일 작업은 열기 전에 이미 절반이 결정된다

성적 파일을 읽으려는 프로그램이 실수로 쓰기 모드 "w"를 선택했다고 가정하자. 파일이 존재하면 이전 내용이 삭제되므로, 뒤에서 아무리 정확한 읽기 함수를 사용해도 원래 자료를 되찾을 수 없다. 따라서 첫 질문은 “어떤 함수를 호출할까?”가 아니라 “기존 파일의 보존, 새 파일 생성, 읽기와 쓰기 중 무엇이 필요한가?”다.

파일(file)은 보조기억장치에 저장된 자료의 모임이다. C에서는 키보드와 모니터 같은 입출력 장치도 파일과 같은 방식으로 다룬다. 프로그램은 장치나 파일의 세부 동작에 직접 매달리지 않고 스트림(stream)이라는 논리적 데이터 통로를 통해 자료를 주고받는다.

첫 판단: 파일 처리 코드를 쓰기 전에 기존 자료를 보존할지, 새로 만들지, 뒤에 추가할지 정한다. 이 결정이 fopen()의 모드를 정하고 이후 가능한 입출력을 제한한다.

스트림은 닫힘에서 열림으로, 다시 닫힘으로 이동한다

파일 입출력은 세 단계로 보이지만 실제로는 각 단계의 성공 여부가 다음 단계의 조건이 된다. fopen()이 성공해야 유효한 파일 포인터를 얻고, 그 포인터가 있어야 입출력하거나 위치를 바꿀 수 있으며, 작업이 끝나면 fclose()로 스트림을 소멸시킨다.

  1. 열기: 파일명과 사용 모드로 fopen()을 호출해 스트림을 만든다.
  2. 확인: 반환값이 NULL인지 검사한다. 실패했다면 입출력 단계로 넘어가지 않는다.
  3. 처리: 문자, 문자열, 형식화 자료 또는 이진 레코드 단위의 함수를 선택한다.
  4. 위치 변경: 랜덤 접근이 필요하면 fseek()로 다음 입출력 위치를 옮긴다.
  5. 닫기: fclose()로 남은 출력 자료를 반영하고 관련 자원을 해제한다.
#include <stdio.h>

int main(void) {
    FILE *fp = fopen("letters.txt", "w");

    if (fp == NULL) {
        fputs("파일을 열 수 없습니다.\n", stderr);
        return 1;
    }

    for (char ch = 'A'; ch <= 'F'; ch++) {
        fputc(ch, fp);
    }

    fclose(fp);
    return 0;
}

이 학습용 예제는 letters.txt에 ABCDEF를 기록한다. 핵심은 fputc()보다 앞선 NULL 검사다. 파일 열기가 실패했는데 fp를 계속 사용하면 이후 호출의 전제가 무너진다.

버퍼는 명령 횟수와 실제 장치 접근을 분리한다

버퍼(buffer)는 자료를 공급하는 쪽과 소비하는 쪽 사이에 두는 임시 기억 공간이다. 프로그램이 출력 함수를 한 번 호출할 때마다 저장 장치에 직접 접근하는 대신 자료를 버퍼에 모았다가 효율적인 시점에 전달할 수 있다. 입력도 장치에서 받은 자료를 버퍼에 두고 프로그램이 필요한 만큼 소비한다.

이 때문에 “출력 함수를 호출했다”와 “저장 장치에 최종 반영되었다”를 같은 순간으로 단정하면 안 된다. fclose()는 버퍼에 남은 출력 자료를 파일에 저장한 뒤 스트림과 관련 자원을 정리한다. 정상 흐름에서 닫기 단계를 빼지 않는 이유다.

역할 구분: 파일은 지속적으로 보관되는 자료의 모임이고, 버퍼는 입출력 과정의 임시 공간이며, 스트림은 프로그램과 외부 대상 사이의 논리적 통로다. 세 용어는 같은 대상을 다른 이름으로 부르는 것이 아니다.

파일 포인터는 파일 내용이 아니라 스트림 정보를 가리킨다

FILE은 파일 처리에 필요한 정보를 담는 구조체형이고, FILE *는 그 정보를 가리키는 포인터형이다. fopen()이 성공하면 파일 포인터를 반환하고, 이후의 파일 함수는 이 포인터를 받아 어느 스트림을 처리할지 구분한다.

FILE *fp;
fp = fopen("scores.txt", "r");

fp 자체가 파일 속의 첫 문자나 파일 전체 내용을 저장하는 것은 아니다. 또한 파일 포인터라는 말과 파일의 현재 입출력 위치를 혼동하지 않아야 한다. fp는 스트림을 식별하는 포인터이고, 스트림 내부에는 다음 읽기나 쓰기가 일어날 현재 위치 정보가 관리된다.

대상무엇을 나타내는가대표 조작
FILE *fp열린 스트림을 식별하는 파일 포인터fopen()의 반환값 저장
현재 입출력 위치다음 읽기·쓰기가 시작될 파일 안의 위치fseek()로 이동
파일 내용저장 장치에 기록된 실제 자료fread(), fwrite() 등으로 전달

열기 모드는 보존·권한·생성 여부를 함께 정한다

모드 문자열은 읽기 또는 쓰기 권한만 표시하지 않는다. 파일이 이미 있을 때 원래 내용을 어떻게 할지, 파일이 없을 때 새로 만들지까지 결정한다. b를 붙이면 같은 접근 목적을 이진 모드로 지정한다.

모드가능한 처리기존 파일없는 파일선택 질문
"r", "rb"읽기내용 유지NULL 반환반드시 기존 자료를 읽는가?
"r+", "rb+"읽기·쓰기내용 유지NULL 반환기존 파일을 보존하며 수정하는가?
"w", "wb"쓰기이전 내용 삭제새 파일 생성처음부터 새로 기록하는가?
"w+", "wb+"읽기·쓰기이전 내용 삭제새 파일 생성새 파일을 만들고 다시 읽는가?
"a", "ab"추가 쓰기끝에 추가새 파일 생성기존 기록 뒤에만 덧붙이는가?
"a+", "ab+"읽기·추가 쓰기끝에 추가새 파일 생성읽기도 하며 새 기록은 뒤에 붙이는가?

+는 기존 모드에 읽기·쓰기 양쪽 기능을 부여하지만, 앞 글자의 파일 생성·보존 규칙까지 없애지는 않는다. 따라서 "r+"와 "w+"는 둘 다 읽고 쓸 수 있어도, 파일이 없을 때와 기존 내용 처리에서 전혀 다른 결과를 낸다.

모드를 고르는 세 질문

  1. 기존 파일이 반드시 있어야 하는가?
  2. 기존 내용을 보존해야 하는가, 전체를 새로 써도 되는가?
  3. 읽기만, 쓰기만, 둘 다, 또는 끝에 추가 중 어떤 작업이 필요한가?

자료 단위를 정하면 입출력 함수가 좁혀진다

파일 함수는 이름이 많지만 처리할 자료 단위로 묶으면 선택이 단순해진다. 한 문자, 한 문자열, 형식이 있는 값, 고정 크기 블록 가운데 무엇을 옮길지 먼저 정한다.

자료 단위입력출력판단 기준
한 문자fgetc(), getc()fputc(), putc()문자를 하나씩 변환하거나 복사할 때
문자열·한 행fgets()fputs()개행을 포함한 줄 단위 텍스트를 다룰 때
형식화된 값fscanf()fprintf()정수·문자열을 서식에 맞춰 읽고 쓸 때
고정 크기 블록fread()fwrite()이진 자료를 크기와 개수로 전달할 때
위치·상태fseek(), feof(), ferror()fseek(), ferror()현재 위치를 옮기거나 종료·오류 원인을 확인할 때

getc()와 putc()는 한 문자용 매크로 형태이고, fgetc()와 fputc()는 한 문자용 함수다. 어느 이름을 택하든 “한 문자”라는 처리 단위는 같다. 함수 선택을 읽기·쓰기 방향과 자료 단위의 두 축으로 정리하면 대응 관계가 보인다.

표준 스트림은 프로그램 시작과 함께 준비된다

일반 파일은 fopen()으로 열어야 하지만 표준 입력·출력·오류 스트림은 프로그램이 시작할 때 자동으로 생성된다. 그래서 별도의 FILE * 선언 없이 곧바로 사용할 수 있다.

표준 파일파일 포인터기본 대응 장치사용 목적
표준 입력stdin키보드프로그램이 자료를 받음
표준 출력stdout모니터정상 결과와 안내를 출력
표준 오류stderr모니터실패 원인과 오류 메시지를 출력
fprintf(stdout, "자료를 입력하세요: ");
fputs("파일 열기 실패\n", stderr);

두 문장 모두 화면에 보일 수 있지만 의미는 다르다. 정상 안내는 stdout, 오류 보고는 stderr로 분리하면 프로그램의 정상 결과와 실패 메시지를 다른 흐름으로 다룰 수 있다.

텍스트 파일은 레코드를 문자와 개행으로 표현한다

텍스트 파일은 자료를 문자 형태로 저장한다. 수치 29도 메모리의 정수 표현을 그대로 쓰는 것이 아니라 문자 '2'와 '9'로 기록한다. 한 행의 길이가 달라도 개행 문자로 레코드의 끝을 구분할 수 있다. 개행이 실제 파일에 저장되는 방식은 운영체제에 따라 달라질 수 있다.

다음은 학번, 이름, 네 점수를 표준 입력에서 받아 텍스트 파일에 형식화해 저장하는 학습용 축약 예제다.

#include <stdio.h>

int main(void) {
    FILE *fp = fopen("scores.txt", "w");
    char no[10], name[10];
    int mid, term, report, attend;

    if (fp == NULL) {
        fputs("파일을 열 수 없습니다.\n", stderr);
        return 1;
    }

    for (int i = 0; i < 3; i++) {
        if (fscanf(stdin, "%9s %9s %d %d %d %d",
                   no, name, &mid, &term, &report, &attend) != 6) {
            fputs("입력 형식이 올바르지 않습니다.\n", stderr);
            fclose(fp);
            return 1;
        }

        fprintf(fp, "%-9s %-9s %3d %3d %3d %3d\n",
                no, name, mid, term, report, attend);
    }

    fclose(fp);
    return 0;
}

fscanf()는 여섯 항목이 모두 변환되었을 때 6을 반환한다. %9s는 10칸 배열에 문자열 끝의 널 문자 한 칸을 남긴다. fprintf()의 폭 지정은 읽기 쉬운 열을 만들지만, 실제 레코드 길이는 값의 자릿수와 개행 표현에 따라 달라질 수 있으므로 이 파일은 처음부터 차례로 처리하는 순차 파일에 알맞다.

이진 파일은 메모리 표현을 크기와 개수로 옮긴다

이진 파일은 자료의 2진 표현을 그대로 저장한다. 수치 자료를 사람이 읽는 문자로 변환하지 않아도 되므로 빠르게 처리할 수 있지만, 저장된 내용을 사람이 직접 읽기 어렵고 시스템 간 표현 차이에 주의해야 한다.

int values[4] = {12, 24, 36, 48};
FILE *fp = fopen("values.dat", "wb");

if (fp != NULL) {
    size_t written = fwrite(values, sizeof(int), 4, fp);
    if (written != 4) {
        fputs("일부 자료를 쓰지 못했습니다.\n", stderr);
    }
    fclose(fp);
}

fwrite(자료버퍼, 레코드길이, 레코드개수, 파일포인터)에서 이 예제의 레코드길이는 sizeof(int), 레코드개수는 4다. 요청한 자료량은 sizeof(int) * 4바이트이며, 반환값은 실제로 기록한 레코드 개수다. fread()도 같은 네 인수 구조로 읽을 버퍼, 한 레코드 크기, 개수, 스트림을 지정한다.

인수 판독법: 두 번째 인수는 한 레코드의 바이트 수, 세 번째 인수는 레코드 수다. 둘을 뒤섞지 말고 “한 개 크기 × 몇 개”로 읽는다.

랜덤 접근은 레코드 번호를 바이트 위치로 바꾼다

순차 파일은 처음부터 저장 순서대로 자료를 읽는다. 반면 강의의 랜덤 파일은 길이가 일정한 레코드를 두고 원하는 위치로 이동해 읽거나 쓴다. 특정 레코드 앞의 자료를 모두 읽을 필요가 없지만, 목표 위치를 바이트 단위로 계산할 수 있어야 한다.

레코드 크기가 REC_SIZE이고 번호를 0부터 센다면 n번째 인덱스의 시작 위치는 다음과 같다.

레코드 시작 오프셋 = 레코드 인덱스 * REC_SIZE
인덱스 0: 0 * REC_SIZE
인덱스 3: 3 * REC_SIZE
인덱스 5: 5 * REC_SIZE

이 식은 “세 번째 레코드”처럼 일상적인 순서 번호와 0부터 시작하는 인덱스를 구분해야 한다. 세 번째 레코드의 인덱스는 2이므로 시작점은 2 * REC_SIZE다. 이 차이를 놓치면 원하는 레코드보다 한 칸 뒤로 이동한다.

고정 길이가 필요한 이유: 앞 레코드의 크기가 제각각이면 n번째 레코드의 시작점을 단순 곱셈으로 알 수 없다. 일정한 레코드 길이가 랜덤 접근의 위치 계산을 가능하게 한다.

fseek는 기준점과 상대 이동량을 결합한다

fseek()는 파일의 현재 입출력 위치를 옮긴다. 두 번째 인수는 기준점에서 얼마나 이동할지를 나타내고, 세 번째 인수가 기준점을 정한다.

fseek(fp, 이동량, 기준점);
기준 기호기준 위치이동량 해석대표 목적
SEEK_SET파일 시작시작점에서 뒤로 이동특정 인덱스의 절대 위치 계산
SEEK_CUR현재 위치양수는 뒤, 음수는 앞으로 이동방금 읽은 위치를 기준으로 건너뛰거나 되돌아감
SEEK_END파일 끝끝을 기준으로 상대 이동끝 부근의 위치 지정

fseek(fp, 3 * REC_SIZE, SEEK_SET)은 파일 시작에서 레코드 세 개 크기만큼 이동한다. fseek(fp, -2 * REC_SIZE, SEEK_CUR)은 현재 위치에서 레코드 두 개만큼 앞으로 되돌아간다. 음수 부호는 레코드 번호가 음수라는 뜻이 아니라 이동 방향이 앞쪽이라는 뜻이다.

읽기 함수가 끝난 뒤의 위치까지 추적해야 한다

강의의 고정 길이 이름 레코드 예제를 상태 변화로 다시 계산해 보자. 한 레코드가 10바이트이고 레코드 인덱스 0부터 4까지 차례로 KIM_HG, PARK_SY, LEE_SY, CHOI_DS, KIM_HS를 저장했다고 가정한다.

  1. fseek(fp, 10 * 3, SEEK_SET)으로 시작점에서 30바이트 이동한다. 현재 위치는 인덱스 3의 CHOI_DS 시작이다.
  2. fread(name, 10, 1, fp)가 레코드 하나를 읽는다. 출력값은 CHOI_DS이고 현재 위치는 다음 레코드인 인덱스 4의 시작으로 전진한다.
  3. fseek(fp, -2 * 10, SEEK_CUR)은 현재 인덱스 4에서 두 레코드 앞으로 되돌아간다. 새 위치는 인덱스 2다.
  4. 다시 레코드 하나를 읽으면 LEE_SY가 나온다.
동작동작 전 위치동작 후 위치읽은 레코드
SEEK_SET으로 30바이트 이동관계없음인덱스 3 시작없음
10바이트 1개 읽기인덱스 3 시작인덱스 4 시작CHOI_DS
SEEK_CUR로 -20바이트 이동인덱스 4 시작인덱스 2 시작없음
10바이트 1개 읽기인덱스 2 시작인덱스 3 시작LEE_SY

두 번째 이동을 처음 위치인 인덱스 3에서 계산하면 인덱스 1이라고 잘못 답하게 된다. fread()도 현재 위치를 읽은 크기만큼 전진시킨다는 사실을 포함해야 전체 흐름이 맞는다.

파일 처리 실패는 반환값이 갈라지는 지점에서 찾는다

파일 코드는 정상 흐름만 적으면 완성되지 않는다. 열기, 변환 입력, 블록 읽기와 쓰기마다 성공 여부를 나타내는 반환값이 있다. feof()는 파일 끝 상태를, ferror()는 입출력 오류 상태를 구분하는 데 사용한다.

int value;
size_t count = fread(&value, sizeof value, 1, fp);

if (count == 1) {
    printf("읽은 값: %d\n", value);
} else if (feof(fp)) {
    fputs("파일의 끝에 도달했습니다.\n", stdout);
} else if (ferror(fp)) {
    fputs("파일을 읽는 중 오류가 발생했습니다.\n", stderr);
}

먼저 fread()가 요청한 레코드 한 개를 실제로 읽었는지 확인한다. 부족했다면 그때 끝 상태와 오류 상태를 구분한다. “파일 끝일 것 같다”는 추측으로 값을 사용하지 않고, 실제 읽기 결과를 기준으로 다음 행동을 결정하는 흐름이다.

진단 순서: fopen()의 NULL, 입출력 함수의 반환 개수, 필요할 때 feof()와 ferror(), 마지막 fclose()를 차례로 확인한다.

새 파일 문제는 여섯 가지 결정으로 설계한다

파일 처리 문제를 만나면 함수 목록부터 떠올리지 말고 다음 결정 순서를 적용한다.

  1. 지속성: 기존 자료를 보존할지, 새로 만들지, 뒤에 추가할지 정한다.
  2. 표현: 사람이 읽을 문자 표현이 필요한지, 메모리 표현의 이진 블록이 필요한지 정한다.
  3. 접근: 처음부터 순차 처리할지, 고정 길이 레코드의 임의 위치로 이동할지 정한다.
  4. 단위: 문자·행·형식화 값·고정 크기 레코드 중 입출력 단위를 고른다.
  5. 위치: 랜덤 접근이면 인덱스 * 레코드 크기와 SEEK_SET, SEEK_CUR, SEEK_END 중 기준을 정한다.
  6. 실패: 열기와 입출력 반환값을 검사하고 모든 정상 종료 경로에서 파일을 닫는다.

예를 들어 “기존 로그는 유지하고 새 행을 덧붙인다”면 문자 표현, 순차 추가, 행 단위 출력이라는 판단을 거쳐 "a"와 fputs() 또는 fprintf()로 좁혀진다. “고정 크기 레코드의 네 번째 항목을 읽는다”면 이진 읽기, 랜덤 접근, 레코드 단위 입력이라는 판단을 거쳐 "rb", fseek(), fread()가 연결된다.

핵심 개념 정리

  • 파일은 지속 자료, 버퍼는 전송 중 임시 공간, 스트림은 프로그램과 외부 대상 사이의 논리적 통로다.
  • 파일 처리는 열기, 성공 확인, 입출력, 필요시 위치 변경, 닫기의 상태 흐름으로 검토한다.
  • FILE *는 열린 스트림을 식별하고, 파일의 현재 위치는 다음 입출력 지점을 나타내는 별도의 상태다.
  • 열기 모드는 읽기·쓰기 권한뿐 아니라 기존 내용 보존, 새 파일 생성과 추가 방식을 함께 결정한다.
  • 텍스트 함수는 문자·행·형식화 값을 다루고, fread()와 fwrite()는 레코드 크기와 개수로 이진 블록을 옮긴다.
  • 랜덤 접근에서는 고정 길이 레코드의 시작점을 인덱스 * 레코드 크기로 계산하고 fseek()의 기준점을 선택한다.
  • 읽기나 쓰기는 현재 위치를 전진시키므로, 연속된 fseek() 계산은 직전 입출력 뒤의 위치에서 시작한다.

파일 문제는 “무엇을 저장할까”에서 끝나지 않는다. 기존 자료를 어떻게 다룰지 정해 모드를 고르고, 문자 또는 이진 표현과 순차 또는 랜덤 접근을 선택한 뒤, 자료 단위에 맞는 함수를 연결한다. 각 호출 뒤에는 반환값과 새 현재 위치를 표시하고 마지막에 스트림을 닫는다. 이 생애와 위치를 한 줄씩 추적하면 모드 실수, 잘못된 함수 선택, 한 레코드 어긋난 탐색과 실패 반환값 무시를 같은 절차로 예방할 수 있다.

예상문제 10선

1. C 파일 처리에서 스트림을 가장 정확하게 설명한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 배열은 프로그램의 자료 저장 객체이며 외부 대상과의 전달 통로 자체가 아니다.
  • ② 오답: 이는 파일에 가까운 설명이고 스트림은 파일과 프로그램을 연결하는 추상화다.
  • ③ 오답: 임시 변수 목록이 아니라 입력과 출력이 흐르는 논리적 연결을 뜻한다.
  • ④ 정답: 스트림을 통해 프로그램은 파일과 콘솔 같은 외부 대상을 공통 방식으로 처리한다.

2. 이미 내용이 있는 report.txt를 fopen("report.txt", "w")로 열면 어떻게 되는가?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 기존 내용 뒤에 덧붙이는 목적에는 "a" 모드를 사용한다.
  • ② 정답: "w"는 쓰기용으로 열면서 존재하는 파일의 이전 내용을 없앤다.
  • ③ 오답: 기존 내용을 읽기만 하는 모드는 "r"이다.
  • ④ 오답: 파일이 없을 때도 새 파일을 만들며, 존재 자체는 실패 조건이 아니다.

3. 일반 파일을 안전하게 출력하는 흐름으로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 스트림을 만든 뒤 성공을 확인해야 유효한 파일 포인터로 출력하고 닫을 수 있다.
  • ② 오답: 열린 스트림이 없는데 먼저 출력하려 하므로 출력 함수의 전제가 성립하지 않는다.
  • ③ 오답: 스트림을 만들기 전에 닫거나 출력할 수 없으며 단계가 거꾸로다.
  • ④ 오답: 검사할 반환값은 fopen() 호출 뒤에 생긴다.

4. 개행을 포함할 수 있는 텍스트 한 행을 크기가 정해진 문자 배열로 읽을 때 가장 알맞은 함수는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 한 문자를 파일에 쓰는 출력 함수이므로 읽기 방향과 자료 단위가 모두 다르다.
  • ② 오답: 고정 크기의 이진 블록을 쓰는 함수이며 텍스트 한 행 입력용이 아니다.
  • ③ 정답: 배열 크기 한계를 지정하면서 텍스트를 행 단위로 읽고 개행도 포함할 수 있다.
  • ④ 오답: 현재 입출력 위치를 옮길 뿐 문자 자료를 배열로 읽지는 않는다.

5. 파일 열기 실패 메시지를 정상 출력과 구분해 보내려 할 때 가장 알맞은 표준 파일 포인터는?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 표준 입력을 받는 스트림이므로 오류 메시지 출력 방향과 맞지 않는다.
  • ② 오답: 정상 결과용 출력 스트림이며 오류를 별도 흐름으로 구분하려는 조건에 부족하다.
  • ③ 오답: 파일 끝을 기준으로 위치를 옮길 때 쓰는 기호이지 파일 포인터가 아니다.
  • ④ 정답: 표준 오류 스트림이므로 실패 메시지를 정상 출력과 의미상 분리한다.

6. int buf[16]; fwrite(buf, sizeof(int), 16, fp);가 요청하는 저장 자료량은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 한 레코드의 크기 sizeof(int)에 레코드 개수 16을 곱한다.
  • ② 오답: 레코드 크기와 개수는 더하는 값이 아니라 전체 자료량을 구하기 위해 곱하는 값이다.
  • ③ 오답: 16은 비트 수가 아니라 기록을 요청한 int 레코드 개수다.
  • ④ 오답: 파일 포인터의 크기가 아니라 자료 배열 요소 하나의 크기를 사용한다.

7. 레코드 크기가 REC_SIZE일 때 인덱스 5인 레코드의 시작 위치로 이동하는 식은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ②

  • ① 오답: 인덱스와 일상적인 순서 번호를 혼동해 한 레코드 앞인 인덱스 4로 이동한다.
  • ② 정답: 시작점을 기준으로 앞선 레코드 다섯 개의 크기만큼 건너뛰면 인덱스 5가 시작된다.
  • ③ 오답: 목표 인덱스에 1을 더해 한 레코드 뒤로 이동한다.
  • ④ 오답: 크기와 인덱스를 더했고 현재 위치를 기준으로 삼아 목표의 절대 위치를 보장하지 못한다.

8. 10바이트 레코드가 KIM_HG, PARK_SY, LEE_SY, CHOI_DS, KIM_HS 순으로 있을 때 다음 코드가 두 번째로 읽는 이름은? 먼저 fseek(fp, 30, SEEK_SET) 후 한 레코드를 읽고, 이어 fseek(fp, -20, SEEK_CUR) 후 한 레코드를 읽는다.

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ④

  • ① 오답: 두 번째 이동은 파일 시작이 아니라 첫 읽기 뒤의 현재 위치를 기준으로 하므로 첫 레코드까지 가지 않는다.
  • ② 오답: 첫 읽기가 위치를 한 레코드 전진시킨 사실을 빼거나 이동량을 세 레코드로 잘못 계산한 결과다.
  • ③ 오답: 이는 30바이트 이동 뒤 첫 번째로 읽는 인덱스 3의 레코드다.
  • ④ 정답: 첫 읽기 뒤 위치는 인덱스 4 시작이고, 20바이트를 되돌리면 인덱스 2의 LEE_SY가 된다.

9. 텍스트 파일과 이진 파일의 차이를 올바르게 설명한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ③

  • ① 오답: 이진 파일도 수치와 문자 등 여러 자료를 2진 표현으로 저장할 수 있다.
  • ② 오답: 핵심 구분은 레코드 길이 하나가 아니라 자료를 문자로 변환해 저장하는지 여부다.
  • ③ 정답: 저장 표현의 차이 때문에 사람의 직접 판독 가능성과 변환 과정에도 차이가 생긴다.
  • ④ 오답: 확장자는 이름의 일부일 뿐 실제 입출력 모드와 저장 표현을 대신 결정하지 않는다.

10. 기존 로그를 보존하면서 새 텍스트 행을 끝에 추가하고, 실패도 검사하려는 설계로 가장 적절한 것은?

정답입니다.

오답입니다. 답안을 다시 선택해 보세요.

정답 및 해설 보기

정답: ①

  • ① 정답: 추가 모드는 기존 내용을 보존해 끝에 쓰고, 열기 검사와 닫기까지 스트림 생애를 완성한다.
  • ② 오답: 쓰기 모드는 기존 로그를 삭제하며 닫기를 생략해 보존과 자원 정리 조건을 모두 어긴다.
  • ③ 오답: 읽기 모드와 이진 블록 입력 함수로는 텍스트 행을 새로 기록할 수 없다.
  • ④ 오답: 이진 읽기 모드는 쓰기를 허용하지 않고 파일 시작 덮어쓰기는 끝에 추가한다는 목적과 반대다.

참고 자료와 작성 기준

이 글은 해당 차시 강의자료를 바탕으로 학습 목적에 맞게 재구성한 비공식 학습자료입니다. 스트림 생애 추적, 파일 모드 선택 질문, 자료 단위별 함수 선택표, 고정 길이 레코드의 오프셋 계산과 fseek() 위치 변화는 학습자가 파일 처리 과정을 직접 판정하도록 새로 구성했습니다.

  • 작성·편집: 올에이클래스 학습연구팀
  • 주요 근거: 한국방송통신대학교 컴퓨터과학과, 「C프로그래밍」 13강 파일처리 함수 강의자료, 2025
  • 보충 자료: 외부 자료를 사용하지 않음
  • 편집 원칙: 올에이클래스 편집 정책
  • 최종 내용 검토: 2026-09-07

댓글