happy coding

[c] 문자와 문자열 본문

self study/언어의 기본부터

[c] 문자와 문자열

yeoonii 2022. 11. 25. 16:02
TCP school 을 보고 정리한 내용입니다.

기본적인 입출력

스트림(stream)

C 프로그램은 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림을 통해 다루는데 이때 스트림은 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미한다. 즉, 운영체제에 의해 생성되는 가상의 연결 고리를 말한다. C언어에서 파일과의 연결을 위한 스트림은 사용자가 직접 생성하고 소멸시켜야 하지만 콘솔 장치에 대한 스트림은 프로그램 실행 할 때 자동으로 생성되며, 프로그램을 종료할 때 자동으로 소멸한다. 기본적으로 제공되는 표준 스트림(standard stream)은 아래와 같다.

stdin 표준 입력 스트림
stdout 표준 출력 스트림
stderr 표준 오류 스트림

EOF (End Of File)

C언어는 운영체제와 상관없이, 파일의 끝에 도달했을 때 언제나 특별한 값을 반환하도록 하는데 그 값을 EOF라고 하며, 실제로 이 값은 -1을 나타낸다. 

파일뿐만 아니라 키보드를 통한 입력 시에도 입력 끝을 알려주는 방법이 필요한데, 대부분의 유닉스(UNIX) 시스템에서는 라인의 시작 위치에서 Ctrl + D 을 누르면 EOF를 발생시킬 수 있고, 윈도우 명령창에서는 해당 라인의 어디에서든 Ctrl + Z 를 누르고 나서 Enter를 누르면 EOF를 발생시킬 수 있다. 

단일 문자 입력 함수

단일 문자 입력 함수(하나의 문자를 입력할 때)에서는 getchar() 함수나 fgetc() 함수를 사용한다.

getchar() 함수

getchar() 함수는 표준 입력 스트림인 키보드로부터 하나의 문자를 입력받는 함수이다.

#include <stdio.h>
int getchar(void);	//함수의 원형

fgetc() 함수

fgetc() 함수는 getchar() 함수와 마찬가지로 표준 입력 스트림인 키보드로부터 하나의 문자를 입력받는 함수이다. 하지만 getchar() 함수와는 달리 문자를 입력받을 스트림을 인수로 전달하여 직접 지정할 수 있으며, 키보드뿐만 아니라 파일을 통해서도 문자를 입력받을 수 있다.

#include <stdio.h>
int fgetc(FILE *stream);	//함수의 원형

 단일 문자 출력 함수

단일 문자 출력 함수(하나의 문자를 출력할 때)는 putchar() 함수나 fputc() 함수를 사용한다.

putchar() 함수

putchar() 함수는 표준 출력 스트림인 모니터에 하나의 문자를 출력하는 함수이다.

#include <stdio.h>
int putchar(int c);	//함수의 원형

fputc() 함수

fputc() 함수는 putchar() 함수와 마찬가지로 표준 출력 스트림이 모니터에 하나의 문자를 출력하는 함수이다. 하지만 putchar() 함수와는 달리 문자를 출력할 스트림을 인수로 전달하여 직접 지정할 수 있으며, 키보드뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있다.

#include <stdio.h>
int fputc(int c, FILE *stream);

문자열(string)

C언어에서 큰따옴표("")를 사용해 표현되는 문자열을 문자열 상수(string constant)라고 한다. 여기서 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않으며, 문자열의 내용 또한 변경할 수 없기 때문이다. 

C언어에서 문자열은 메모리에 저장된 일련의 연속된 문자(character)들의 집합을 의미하며, 문자형 배열을 선언하면 이 배열은 문자열 변수가 된다.

char str01[] = "This is a string";	//크기를 지정하지 않은 문자열 변수 선언
char str02[7] = "string";		//크기를 지정한 문자열 변수 선언

널(NULL) 문자

문자형 배열로 선언된 문자열 변수는 문자열의 끝을 프로그램에 따로 알려주어야 한다. 그래야만 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레기값을 구분할 수 있다. 따라서 C언어에서는 문자열에 속한 데이터가 끝나면 문자열의 끝을 의미하는 문자를 하나 더 삽입하는데, 이 문자를 널(NULL) 문자라고 하며, '\0'으로 표시하고 아스키코드값은 0이다.

문자열 입력 함수

fgetc() 함수

fgetc() 함수는 키보드뿐만 아니라 파일에서도 문자열을 입력받을 수 있는 함수이다.

#include <stdio.h>
char *fgets(char * restrict s, int n, FILE * restrict stream);	//함수의 원형

fgetc() 함수의 첫 번째 인수는 입력받는 문자열을 저장하기 위해 선언한 배열의 시작 주소를 전달하며,  두 번째 인수는 입력받을 수 있는 문자열의 최대 길이를 전달하고, 마지막 인수는 문자열을 입력받을 스트림을 전달한다.

문자열 출력 함수

puts() 함수

puts() 함수는 표준 출력 스트림인 모니터에 하나의 문자열을 출력하는 함수이다. 이 함수는 모니터에 문자열을 출력한 다음에 자동으로 줄을 바꿔준다. 이 함수는 인수로 출력할 문자열을 가리키는 포인터를 전달한다.

#include <stdio.h>
int puts(const char *s);	//함수의 원형

fputs() 함수

fputs() 함수는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있는 함수이다. 이 함수는 puts() 와 달리 문자열을 출력한 다음에 자동으로 줄을 바꿔주지 않는다.

#include <stdio.h>
int fputs(const char * restrict s, FILE * restrict stream);	//함수의 원형

이 함수의 첫 번째 인수는 출력할 문자열을 가리키는 포인터를 전달하며, 두 번째 인수로는 문자열을 출력할 스트림을 전달한다.

문자열 처리 함수

C언어에서 문자열이란 마지막에 널 문자를 가지는 문자형 배열로 표현되며, 기본 타입에는 포함되지 않기에 C 컴파일러가 기본 타입을 위해 제공하는 다양한 연산자를 자유롭게 사용할 수 있다. 이 때문에 C언어는 문자열을 처리하기 위한 다양한 함수를 별도로 제공하고 있다.

strlen() 함수

이 함수는 인수로 전달된 문자열의 길이를 반환하는 함수이다. 이때 문자열 여부를 구분하는 마지막 문자인 널 문자는 문자열의 길이에서 제외된다. 

#include <string.h>
size_t strlen(const char *s);	//함수의 원형

strcat() 함수와 strncat() 함수

이 함수들은 하나의 문자열에 다른 문자열을 연결해주는 함수이다.

#include <string.h>
char *strcat(char * restrict s1, const char * restrict s2);	//함수의 원형

char *strncat(char * restrict s1, const char * restrict s2, size_t n);	//함수의 원형

strcat() 함수의 첫 번째 인수로 전달된 문자열은 기준 문자열이 되며, 두 번째 인수로 전달된 추가하고자 하는 문자열의 복사본이 기준 문자열 뒤에 추가된다.

함수의 원형에서 볼 수 있는 restrict 키워드는 포인터의 선언에서만 사용할 수 있는 C99로부터 추가된 키워드이다. 포인터를 선언할 때 이 키워들 명시하면, 컴파일러는 해당 포인터가 가리키는 메모리에 대한 최적화를 실시한다.

여기서 배열 오버 플로우(overflow, 기존 문자열이 저장된 배열의 공간이 충분하지 않다면 배열을 채우고 남은 문자들이 배열 외부로 흘러 넘치는 현상)를 방지하기 위해 strcat() 함수 대신에 strncat() 함수를 사용하는 것이 좋다.

strncat() 함수의 세 번째 인수로 추가할 문자열의 최대 길이를 지정할 수 있으며, 이외의 하는 일은 같다. 이 함수는 널 문자를 만나거나, 추가하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 도달할 때까지 추가를 계속한다.

strcpy() 함수와 strncpy() 함수

이 함수는 문자열을 복사하는 함수이다.

#include <string.h>
char *strcpy(char * restrict s1, cont char * restrict s2);	//함수의 원형

char *strncpy(char * restrict s1, const char * restrict s2, size_t n);	//함수의 원형

strcpy() 함수는 첫 번째 인수로 전달된 배열에, 두번째 인수로 전달된 문자열을 복사한다. 하지만 이때 첫 번째 인수로 전달된 배열의 크기가 복사할 문자열의 길이보다 작으면, 배열 오버플로우가 발생하기 때문에 이를 방지하기 위해 strcpy() 함수 대신에 strncpy() 함수를 사용하는 것이 좋다.

strncpy() 함수는 strcpy() 함수와 하는 일은 같지만, 세 번째 인수로 복사할 문자열의 최대 길이를 지정할 수 있다. 이 함수는 널 문자를 만나거나, 복사하는 문자의 개수가 세 번째 인수로 전달된 최대 길이에 도달할 때까지 복사를 계속한다.

char str01[20] = "C is Cool!";
char str02[11];  

//str02 배열의 크기만큼만 복사를 진행하며, 마지막 한 문자는 널 문자를 위한 것임
strncpy(str02, str01, sizeof(str02)-1);
str02[sizeof(str02)-1] = '\0'; //이 부분을 주석 처리하면, 맨 마지막에 널 문자를 삽입하지 않음
puts(str02);

위 예제는 strncpy() 함수를 이용해 문자열의 일부분만 복사하는 예제이다. 이렇게 복사한 문자열의 마지막에는 반드시 널 문자를 삽입해 주어야만 C 프로그램이 제대로 문자열로 인식할 수 있다.

char str[20] = "C is cool!";  
strncpy(str+5, "nice", 4); // 배열 이름을 이용한 포인터 연산으로 수정할 부분의 시작 부분을 지정함
puts(str);

위 예제는 strncpy() 함수를 이용해 문자열의 일부분만을 수정하는 예제이다. 첫 번째 인수에 배열 이름을 이용한 포인터 연산을 사용하여 수정을 시작할 지점을 지정할 수 있다.

strcmp() 함수와 strncmp() 함수

이 함수들은 문자열의 내용을 비교하는 함수이다.

#include <string.h>
int strcmp(const char *s1, const char *s2);	//함수의 원형
int strncmp(const char *s1, const char *s2, size_t n);	//함수의 원형

strcmp() 함수는 인수로 두 개의 문자열 포인터를 전달받아, 해당 포인터가 가리키는 문자열의 내용을 서로 비교한다. 두 문자열의 모든 문자는 아스키 코드값으로 자동 변환되며, 문자열의 맨 앞에서부터 순서대로 비교된다. 반환값에 따른 설명은 아래 표에 정리해 두었다.

양수 첫 번째 인수로 전달된 문자열이 더 큰 경우
0 두 문자열의 내용이 완전히 같은 경우
음수 두 번째 인수로 전달된 문자열이 더 큰 경우

strncmp() 함수는 strcmp() 함수와 하는 일이 같지만, 세 번째 인수로 비교할 문자의 개수를 지정할 수 있다. 이 함수는 일치하지 않는 문자를 만나거나, 세 번째 인수로 전달된 문자의 개수만큼 비교를 계속한다.

atoi(), atol(), atoll(), atof() 함수

이 함수들은 인수로 전달된 문자열을 해당 타입의 숫자로 변환시켜주는 함수이다.

#include <stdlib.h>
int atoi(const char *nptr);		//int형 정수로 변환
long int atol(const char *nptr);	//long형 정수로 변환
long long int atoll(const char *nptr);	//long long형 정수로 변환
double atof(const char *nptr);		//double형 실수로 변환

toupper() 함수와 tolower() 함수

이 함수들은 인수로 전달된 문자열의 영문자를 모두 대문자나 소문자로 변환시켜주는 함수이다.

#include <ctype.h>
int toupper(int c);	//문자열의 모든 영문자를 대문자로 변환
int tolower(int c);	//문자열의 모든 영문자를 소문자로 변환

 

'self study > 언어의 기본부터' 카테고리의 다른 글

[c] 포인터와 구조체  (0) 2022.11.26
[c] 구조체의 기본  (0) 2022.11.26
[c] 메모리 관리  (0) 2022.11.22
[c] 포인터와 배열  (0) 2022.11.22
[c] 포인터  (0) 2022.11.21
Comments