inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

홍정모의 따라하며 배우는 C언어

13.2 텍스트 파일 입출력 예제

인자부족으로 인한 종료

해결된 질문

96

hahahl

작성한 질문수 21

1

#define CRTSECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char* argv[])

{

int ch;

FILE* fr; // TODO: file pointer to write

FILE* fw;

const char* out_filename = "output.txt";

unsigned long count = 0;

if (argc != 3)

{

printf("Usage: %s filename\n", argv[0]);

exit(EXIT_FAILURE);

}

if ((fr = fopen(argv[1], "r")) == NULL) // Open a text file for reading.

{

printf("Can't open %s\n", argv[1]);

exit(EXIT_FAILURE);

}

if ((fw = fopen(argv[2], "w")) == NULL)

{

printf("Can't open %s\n", argv[2]);

exit(EXIT_FAILURE);

}

/*

r: reading

w: creating and writing or over writing

a: appending or creating and writing

r+: both reading and writing

w+: reading and writing, over writingor creaitng

a+: reading and writing, appending or creating

*/

while ((ch = fgetc(fr)) != EOF) // getc(fr)

{

fputc(ch, stdout);

fputc(ch, fw);

count++;

}

printf("\n");

fclose(fr);

fclose(fw);

printf("File %s has %lu characters\n", argv[1], count);

printf("Copied to %s", out_filename);

return 0;

}

질문) 출력 조건문에서 out_filename대신 argv[2]를 대신 사용하려면 printf("Usage: %s filename\n", argv[0]); 이 부분 조건문 부분의 인자를 3으로 해야 안전하게 데이터를 보호할 수 있는 것으로 알고 있는데 이렇게되면 파일이 없는 경우 생성이 되기전에 프로그램이 종료가 되는 문제점이 발생합니다. 이 상황에서 argv[2]를 사용하려고 하면 코드를 어떻게 구성해야 프로그램이 정상작동될까요?

c

답변 1

2

Soobak

안녕하세요? 질문&답변 도우미 Soobak 입니다.

 

좋은 고민이시네요.
우선, 말씀해주신 내용 중 '파일이 없는 경우 생성되기 전에 프로그램이 종료가 되는 문제점이 발생' 부분에서 '파일이 없는 경우' 라는 표현보다는, 'argv[2] 인수가 없는 경우', 즉, '출력하려는 파일의 이름'이 인수로 전달되지 않은 경우 로 생각해보시면, 해결 방법을 떠올리시는 것이 보다 편하실 것 같습니다.

 

문제는 다양한 방법으로 해결할 수 있을 것 같습니다.
argv[2] 를 활용하여 출력 파일의 이름을 반드시 지정하도록 변경하시는 것이 의도이시라면,
말씀해주신 내용처럼 argc3 이 아닌 경우에 대해서 Usage: 프로그램이름(argv[0]) filename 을 출력하고 프로그램을 종료하는 부분을 Usage: 프로그램이름(argv[0]) 읽을파일이름 출력할파일이름 등과 같이 수정하여, 사용자가 argv[2] 도 함께 입력해야 됨을 알 수 있도록 사용자 친화적으로 변경하는 방법이 있을 것 같습니다.

또는 일종의 '기본값' 설정처럼, argc2 인 경우, 즉, 읽어들일 파일의 이름만 인수로 전달된 경우에는 현재와 같이 "output.txt" 문자열을 생성 파일의 이름으로 사용하되, argc3 인 경우, 즉, 출력 파일의 이름 또한 인수로 전달된 경우에는 "output.txt" 대신 argv[2] 를 생성 파일의 이름으로 사용하도록 구성할 수도 있을 것 같습니다.

1

hahahl

정확히 이해한 것인지 모르겠지만 수정해보았습니다.

#define CRTSECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char* argv[])

{

int ch;

FILE* fr; // TODO: file pointer to write

FILE* fw;

const char* out_filename = "output.txt";

unsigned long count = 0;

if (argc < 2 || argc > 3)

{

printf("Usage: %s 읽을파일이름 [출력할파일이름]\n", argv[0]);

exit(EXIT_FAILURE);

}

if ((fr = fopen(argv[1], "r")) == NULL) // Open a text file for reading.

{

printf("Can't open %s\n", argv[1]);

exit(EXIT_FAILURE);

}

if (argc == 3)

{

out_filename = argv[2];

}

if ((fw = fopen(out_filename, "w")) == NULL)

{

printf("Can't open %s\n", out_filename);

exit(EXIT_FAILURE);

}

/*

r: reading

w: creating and writing or over writing

a: appending or creating and writing

r+: both reading and writing

w+: reading and writing, over writingor creaitng

a+: reading and writing, appending or creating

*/

while ((ch = fgetc(fr)) != EOF) // getc(fr)

{

fputc(ch, stdout);

fputc(ch, fw);

count++;

}

printf("\n");

fclose(fr);

fclose(fw);

printf("File %s has %lu characters\n", argv[1], count);

printf("Copied to %s", out_filename);

return 0;

}

0

Soobak

네, 잘 이해하시고 작성하셨습니다.

강의의 내용에서 더 나아가 능동적으로 재밌게 학습하시는 것 같아, 저 또한 재미를 느끼네요. 감사합니다.

우선, 첨부해주신 코드를 컴파일 후 실행해보며 여러가지 경우를 체크해보았습니다.
이를 바탕으로, 문제가 발생할 '수' 도 있는 상황에 대해서 말씀드려봅니다.

 

const char* out_filename 에서의 자료형에 관한 문제입니다.
이렇게 const 로 한정한 포인터 변수에 대해서 추후 argv[2] 를 할당하는 것은 C언어에서 '문법적으로' 문제가 되지는 않지만, const 로 한정하는 것의 의미에 일치하지 않으며 추후 혼동을 일으킬 수 있으므로 권장되지 않는 방식입니다. (이 부분은 강의 10.5 포인터의 호환성17:50 부분의 교수님 설명을 참고해보시면 이해에 도움이 많이 되실 것 같습니다.)

따라서, chsr* out_filename 을 선언하고, 문자열을 동적으로 할당해주는 것이 보다 더 좋은 코드라고 생각합니다.

 

이미 훌륭하게 작성하셨기에, 이해를 조금 도와드리기 위한 예시 코드를 첨부드려봅니다.

이해를 위해 답변드렸던 이전 답변의 내용의 일관성을 위하여, 로그 부분은 영어가 아닌 한글로 통일하여 작성하였습니다.

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 4096
#define DEFAULT_OUT_FILENAME "output.txt"

int main(int argc, char* argv[])
{
    FILE* fr;
    FILE* fw;
    char buffer[BUFFER_SIZE];
    size_t bytes_read;
    char* out_filename;
    unsigned long count = 0;

    if (argc < 2 || argc > 3)
    {
        fprintf(stderr, "사용법: %s 읽을파일이름 [출력할파일이름]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if ((fr = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "%s 파일을 열 수 없습니다\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    if (argc == 3)
    {
        out_filename = strdup(argv[2]);
    }
    else
    {
        out_filename = strdup(DEFAULT_OUTPUT);
    }

    if (out_filename == NULL)
    {
        fprintf(stderr, "문자열 메모리 할당 실패\n");
        fclose(fr);
        exit(EXIT_FAILURE);
    }

    if ((fw = fopen(out_filename, "w")) == NULL)
    {
        fprintf(stderr, "%s 파일을 열 수 없습니다\n", out_filename);
        free(out_filename);
        fclose(fr);
        exit(EXIT_FAILURE);
    }

    while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, fr)) > 0)
    {
        fwrite(buffer, 1, bytes_read, stdout);
        fwrite(buffer, 1, bytes_read, fw);
        count += bytes_read;
    }

    printf("\n");
    fclose(fr);
    fclose(fw);

    printf("%s 파일은 %lu 바이트입니다\n", argv[1], count);
    printf("%s 파일로 복사되었습니다\n", out_filename);

    free(out_filename);
    return 0;
}

 

Export template 안됨

1

33

2

완전히 똑같이 따라해도 exe파일이 안만들어져서 실행이 안됩니다.

1

58

3

main 함수에서 왜 int만 선언이 되는걸까요

1

58

2

8비트 2진수 변환시 왜 1을 더해야하나요?

1

55

2

혹시 강의를 빠르게 수강하려면 어디서부터 듣는게 좋을까요?

1

50

1

프로토타입과 함수간의 인자 불일치

1

74

2

12.12 헤더 관련 질문

1

61

2

Visual Studio Community 2026 사용 문의

1

139

2

Q. 15:30, 부호가 있는 8비트 정수 질문

1

62

2

getchar(), putchar()

1

95

3

강의자리ㅛ

1

81

2

비주얼스튜디오코드로 공부해도 상관없나요?

1

115

2

소스파일안에 여러 파일

1

77

2

F5와 F7의 차이

1

80

2

c = TWO * (a+b); 에서 a와 b는?

1

61

2

; 세미콜론을 붙이는 기준에 문의

1

71

1

Step over 기능 문의

1

54

2

2.6 강의 따옴표 출력 규칙 문의

1

77

2

int main 함수 관련 오류 문의

1

68

2

13.4 words[0]

0

62

2

11.7 함수를 구현해 봤습니다.

1

63

2

11.6 직접 strcmp와 strncmp를 구현해 보았습니다.

1

66

2

11.6 my_strcat과 my_strncat을 구현해봤습니다.

1

54

2

11.6 fit_str함수를 구현해 봤습니다.

1

55

2