[C언어] #5 입력 (콘솔 입력, 파일입출력, 커맨드라인)
입력의 출처는 어디?
- 스트림(콘솔, 파일) 문자열 등
입력처리 전략
1. 한 글자씩 읽기
- 입력이 문자/문자열일 때 좋음
- 다른 데이터형은 좀 쓰기 어려울수도 (숫자 1004를 문자 하나씩..?)
- 쓸데없이 메모리에 입력값을 저장하지 않아도 된다.
- for문 한번으로 처리가능 O(N)
- 사용예시
int c;
c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
- 입력을 하면 buffer에 문자열이 들어간다.
- 엔터(개행문자)를 치면 입력이 종료되고 버퍼에 값이 있으면 하나씩 읽어서 출력한다. (읽은 값이 EOF이면 종료)
- EOF는 특별한 단축키로 사용 (윈도우
ctrl + z
, 유닉스(리눅스)ctrl + d
)
- EOF는 특별한 단축키로 사용 (윈도우
- 버퍼에 값이 없으면 다시 입력을 대기한다.
getchar()
int getchar(void)
- 반환값이
int
형- EOF : 입력의 끝을 나타내는 값
- C 표준에 따르면 EOF는 음수인데
char
형은 부호가 있을 수도 있고 없을 수도 있기 때문에int
형을 반환해야만 한다.
- 키보드로부터 문자를 하나읽음
- 성공시 읽은 문자의(아스키코드) 반환
- 실패시, EOF를 반환
2. 한 줄씩 읽기
하나씩 읽는 것 보다 한 줄씩 읽는 게 빠름
- CPU를 벗어나 외부 구성요소에서 뭔가를 읽어올 때는 한번에 많이 읽어오는게 빠름.
- 따라서 버퍼 크기가 충분히 큰 것이 좋다.
한 데이터씩 읽어오는 것과 같이 사용하면 유용하다. (안전하게 사용가능)
한 줄을 읽어오면 저장할 공간을 함수가 할당해주지 않는다.
- 함수를 사용만 하고 메모리 해제하지 않으면 메모리 누수 문제가 발생할 수 있기 때문에
- 미리 만든 배열을 함수에 전달해야 한다.
gets()
char* gets(char* str);
-
콘솔에서
\n
또는EOF
를 만날 때까지 계속 문자들을 읽어서 str 배열에 저장 (개행문자는 저장안함 대신\0
저장) -
마지막 문자 뒤에
\0
문자 넣어줌 -
성공시, str
-
실패시 NULL 포인터
-
매우 위험한 함수, 그냥 사용안하면 됨 (C11 부터 사라짐)
-
위험한 이유는 버퍼 사이즈 이상의 입력이 들어오면 버퍼오버플로우 발생, 이를 통제할 방법이 없다.
-
버퍼오버플로우
-
stdin --> str (stdin사이즈가 더 크면 str 뒤쪽메모리까지...)
-
버퍼로 잡아놓은 사이즈를 초과해서 다른 메모리를 키보드 입력으로 덮어씌워버린다.
-
함수 내부에 다른 용도로 잡아놓은 메모리주소(매개변수, 돌아갈 함수 주소, 베이스 포인터)에 값이 변경되어 버릴수 있다!
-
이를 악용한 보안 공격도 가능(버퍼오버플로우 어택)
-
-
fgets()
char* fgets(char* str, int count, FILE* stream);
- 최대 count-1개의 문자열만 읽어서 str에 저장
- str의 길이보다 count가 더 크다면 gets()함수와 동일한 문제 발생할 수 있다.
- str에 개행문자까지 저장해준다.
- 키보드 입력을 읽어오고 싶다면
stdin
을 스트림에 넣어주면됨.
#define LINE_LENGTH(10);
char line[LENGTH];
while(fgets(line, LINE_LENGTH, stdin) != NULL){
printf("%s", line);
}
- 엔터 입력시 까지 계속 입력받는다.
- 버퍼에 값이 있다면 line에 지정한 숫자만큼만 배열에 넣어주고 종료문자열 삽입.
- 버퍼에 값이 없다면 종료
3. 한 데이터씩 읽기
콘솔 입력으로부터 읽음
int scanf(const char* format ...)
파일 스트림으로부터 읽음
int fscanf(FILE* stream, const char* format ...)
C스타일 문자열로부터 읽음
int sscanf(const char* buffer, const char* format ...)
scanf()
- 반환하는 값은 읽은 데이터의 개수를 반환
- 원본을 직접 변경하기 때문에 주소값을 전달
- 복사된 매개변수를 전달해서 값을 변경해봤자.. 함수 종료시 사라진다.
- 데이터의 구분을 공백문자로 하기때문에 모든 공백문자는 사라진다.
- %c로 한 문자씩 읽을 때만 공백문자 저장가능
- 배열크기 보다 큰 데이터가 입력으로 들어오면.. 버퍼 오버플로
- 입력에 실패하면 그 위치에 포인터를 가지고 있기 때문에 무한루프에 빠질 가능성이 꽤 높다.
fgets()와 sscanf()를 같이 사용하면 좋다.
#define LINE_LEGNTH(1024);
int sum = 0;
int num;
char line[LINE_LENGTH];
while(TRUE){
if(fgets(line, LINE_LENGTH, stdin) == NULL){
clearerr(stdin);
break;
}
if (sscanf(line, "%d", &num) == 1){
sum += num;
}
}
4. 한 블록씩 읽기(이진 데이터)
이진 데이터를 읽는 방법
- 파일 형태
size_t fread(void* buffer, size_t size, size_t count, FILE* stream);
size
바이트짜리 데이터를 총 count
개수만큼 읽어서 buffer
에 저장
EOF
를 만나면 멈춤
int nums[64];
size_t num_read;
FILE* fstream; // 파일 스트림
num_read = fread(nums, sizeof(nums[0]), 64, fstream);
fwrite(nums, sizeof(nums[0]), 64, fstream);
파일입출력
C언어에서 파일다루기
- 파일을 열어서 파일 스트림을 가져옴
- 파일 스트림을 사용해서 하고 싶은 걸 한다
- 그 파일을 닫아줌
파일열기
FILE* fopen(const char* filename, const char* mode);
파일을 열고 꼭 닫아줘야한다.
- 파일은 운영체제가 열어주는 것.
- 운영체제는 우리가 언제 파일을 다써서 필요없는지 알 수 없다.
- 계속 파일을 열기만 하면 어느순간 더 이상 파일을 열 수 없다며 뻗을 수 있다.
- 프로그래머의 습관이 가장 중요하다(여는 코드를 작성하는 동시에 닫는 코드도 같이 작성)
파일열기에 실패하면 리턴값은 NULL포인터
파일닫기
int fclose(FILE* stream);
입출력 리디렉션
모든 프로그램은 실행될 때 3개의 스트림이 생성된다. (stdin
stdout
stderr
)
키보드 입력을 파일에서, 콘솔 출력을 파일로 (소스변경없이, fopen이런거 없이!)
C언어의 기능이 아니라 커맨드라인, shell의 기능
파일을 다 읽으면 EOF가 자동으로 추가
리디렉션 != fopen()
> a.exe < input.txt > output.txt 2> error.txt
stdin : <
사용( input.txt에 있는 데이터를 키보드입력처럼 사용하기 )
stdout : >
사용 (콘솔출력을 output.txt에 기록하기)
stderr : 2>
사용 (콘솔출력을 error.txt에 기록하기)
Author And Source
이 문제에 관하여([C언어] #5 입력 (콘솔 입력, 파일입출력, 커맨드라인)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ilhoon93/C언어-입력-콘솔-입력-파일입출력-커맨드라인저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)