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()라는 함수를 통해 인자로 받은 문자열과 함께 오류 메시지를 출력해볼 수도 있다.