Oh-My-C-Lang - Section 6 - 05
42 Starter 스터디 모임에서 진행하는 C 언어 A to Z 스터디에 내용을 정리해서 포스팅을 진행합니다.
해당 스터디에서는 42 Piscine 과정에서 채우지못한 부족한 C언어 역량을 키우는 것을 목적으로 합니다.
출력
int fprintf(FILE *stream, const char *format, ...)
int printf(const char *format, ...)
int sprintf(char *str, const char *format, ...)
fprintf()
: 정해진 파일 스트림에 문자열을 포맷하여 출력 printf()
: 표준 출력(stdin)에 문자열을 포맷하여 출력 sprintf()
: 특정 문자열에 문자열을 포맷하여 출력
printf()
의 포맷팅%[플래그][너비][.숫자 정밀도 | .문자열 최소/최대 출력 개수][길이]서식 지정자 ex.
float f = 10.5123f; printf("%03.2f", f);
sprintf()
의 위험성sprintf()
는 특정 문자열에 출력을 하는 방식이기 때문에 특정 문자열의 길이가 모자르게 된다면, 버퍼 오버플로우가 일어날 수 있다.
기타 출력함수로 마지막에 개행문자를 추가로 출력해주는 puts
, fputs
가 있고 putchar
와 같이 단어를 출력하는 함수가 있다.
입력
한글자씩 읽기
int getchar(void)
getchar()
가 대표적으로 있고 그외로getc()
와fgetc()
가 있다.입력이 문자/문자열일 때 매우 유용하고 메모리에 입력 값을 저장하지 않는다.
하지만 다른 데이터형의 연산이 복잡하다는 단점이 있다.
getchar()
를 이용하여 한글 입력받기
한글은 UTF-8 기준으로 3바이트를 차지한다. 따라서 아스키 코드가 아닌경우 한글로 인식하여 3바이트로 읽어야한다.
아래는 단순히 한글만 입력했을 때를 가정하고 만든 코드이다.
#include <stdio.h> int main(void) { char str_arr[4] = { 0, }; char test_hangul[] = "가"; // UTF-8 "가" --> 3바이트, 문자열이니깐 '\0' + 1바이트 : 총 4바이트 printf("size : %lu\n", sizeof(test_hangul)); // size : 4 printf("values : %d %d %d %d\n", test_hangul[0], test_hangul[1], test_hangul[2], test_hangul[3]); printf("test : %s\n", test_hangul); // "test : 가" 가 출력됩니다. while (1) { printf("\nEnter hangul : "); while ((str_arr[0] = getchar()) == '\n'){} if (str_arr[0] == EOF) { printf("Good Bye!!\n"); break ; } str_arr[1] = getchar(); str_arr[2] = getchar(); printf("\n--------------------------\n"); printf("values : %X %X %X %X\n", str_arr[0], str_arr[1], str_arr[2], str_arr[3]); printf("answer : %s\n", str_arr); printf("--------------------------\n"); } }
한 줄씩 읽기
char* fgets(char* str, int num, FILE* stream)
대표적으로
fgets()
가 있다.fgets()
는 num - 1 까지만 읽거나'\n'
또는EOF
까지 읽는다.사용시에 항상
str
의 길이 이상만큼이 담겨지지 않도록 주의해야한다.*추가정보 : FILE 자료형 - 스트림을 제어하기 위해 필요한 정보를 담고 있는 자료형 다음과 같은 역할을 갖고있다.
- 파일의 위치를 표시
- 스트림이 사용하는 버퍼의 포인터
- 읽기/쓰기 중에 발생한 오류를 기록하는 표시자
- 파일의 끝에 도달했음을 기록하는 EOF 지시자
*추가정보 :
fgets
는puts
와 궁합이 맞지 않는다. 그 이유는fget
자체적으로'\n'
까지 읽도록 설계가 되었는데puts
함수는'\n'
을 추가로 출력하므로 개행문자가 하나가 더 출력이 될 수가 있다.한 데이터씩 읽기
int scanf(const char *format, ...)
int fscanf(FILE *stream, const char *format, ...)
int sscanf(const char *str, const char *format, ...)
scanf()
: 표준 입력에서 문자열을 받아와 포맷팅한다.fscanf()
: 지정한 파일 스트림에서 문자열을 받아온다.sscanf()
: 문자열에서 포맷팅 방식으로 읽어온다.세개의 함수 모두 반환값으로 몇개의 데이터를 읽었는지를 받아오고 만약 실패했다면,
EOF
를 반환한다.scanf()
의 포맷팅은 다음과 같다.%[*][너비][길이]서식지정자
여기서
*
를 사용하게되면 입력한 내용을 받기는 하지만 지나간다는 의미이다.'\n'
을 무시하는 방법으로도 사용된다.scanf
를 사용할 때 문자열의 입력같은 경우 문자열에 받은 입력을 모두 넣으므로 버퍼 오버 플로우가 발생할 수 있다. 따라서 이것을 주의해야하고fgets
를 통해 정해진 길이만큼을 받고sscanf
를 사용하여 해당 문자열을 원하는 포맷팅으로 이용하여 사용하는 것이 좋다.아래는
fgets
와sscanf
를 사용한 예시 코드이다.#include <stdio.h> int main(void) { char buffer[20]; int num1; int num2; while (1) { printf("Enter string : "); fgets(buffer, 20, stdin); sscanf(buffer, "hello %d %d", &num1, &num2); printf("answer : %s\n", buffer); printf("answer : %d %d\n", num1, num2); } return (0); }
*추가정보 :
clearerr()
를 통해EOF
표시자를 리셋 할 수 있다.한 블록씩 읽기
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
파일 스트림을 이용한다. 한꺼번에 읽기 때문에 성능적으로 더 효율적이고 자료형의 바이트 크기가 시스템마다 다르기 때문에 주의해야한다.
다음과 같은 순서로 파일 스트림을 다룬다.
파일을 열어서 파일 스트림을 가져온다.
FILE *fopen(const char *filename, const char *mode)
를 통하여 파일 스트림을 가져온다.파일 스트림으로 하고 싶은 작업을 진행한다.
fread(), fwrite(), fgets() ...
파일 스트림을 닫는다.
int fclose(FILE *stream)
성공하면 0, 실패하면
EOF
를 반환한다.
*추가정보: 42에서
read
또는write
를 사용할 때 성능을 고려한다면 버퍼의 크기를 크게하여 한번에read
또는write
를 사용하는것이 빠르다.에러 처리
에러는
stdin
와stdout
과 같은stderr
라는 스트림을 사용한다,stdout
과 매우 유사하지만stderr
는 버퍼링을 사용하지 않는다.따라서
stdout
과stderr
를 혼용해서 사용하게된다면stderr
버퍼에 출력하기 이전에stdout
버퍼를 비우고 출력을 해야 콘솔 창에서 둘의 값이 섞이지 않는다.*추가정보:
errno
라는 전역 변수를 사용하여 어떤 이유로 실패했는지 숫자로 나타낸 값을 알 수 있다.<errno.h>
에 정의되어 있으며strerr(errno)
를 통하여 어떤 이유로 실패했는지에 대한 숫자 값을 문자열로 알려준다.perror()
라는 함수를 통해 인자로 받은 문자열과 함께 오류 메시지를 출력해볼 수도 있다.