""를 이용해 표현되는 문자열을 문자열 상수(string constant)라고 한다. 이를 상수라고 표현하는 이유는 해당 문자열이 이름을 가지고 있지 않고, 문자열의 내용 또한 변경할 수 없기 때문이다.
string은 메모리에 저장된 일련의 연속된 문자(character)들의 집합을 의미하기에 문자열 배열을 선언하면 이 배열이 곧 문자열 변수가 된다.
char strA[] = "This is a string."; // 크기를 지정하지 않고 문자열 변수 선언
char strB[7] = "string"; // 크기를 지정하여 문자열 변수 선언
printf("문자열 상수\n");
printf("문자열strA에 저장되어 있는 문자열 : %S\n", strA);
printf("문자열strB에 저장되어 있는 문자열 : %S\n", strB);
printf() 함수에서 사용된 "%s"는 문자열 표현을 위한 입출력 서식 문자임
C언어에서는 문자열에 속한 데이터가 끝나면 문자열의 끝을 의미하는 문자를 하나 더 삽입한다. 이 문자를 널(NULL)이라 하며, '\0'이라쓰고 아스키코드값은 0이다. 이렇게 끝을 프로그램에게 알려줌으로써 프로그램이 실제 문자열에 속한 값과 그 외의 쓰레기값을 구분할 수 있게끔 한다.
int str_len = 0;
char str[] = "string";
while (str[str_len] != '\0') { // 널 문자가 나올 때까지 길이를 증가함
str_len++; }
printf("이 문자열의 길이는 %d입니다.\n", str_len);

위의 사진은 사용된 문자열이 메모리 상에 저장되어있는 것을 보여준다.
C언어에서 문자열을 입력할 때에는 fgets()함수를 사용한다. 이는 키보드의 입력뿐만이 아닌 파일에서도 문자열을 입력받을 수 있는 함수이다.
#include <stdio.h>
char *fgets(char *restrict s, int n, FILE *restrict stream);
char *restrict s : 입력받는 문자열의 저장을 위해 선언한 배열의 시작주소를 전달int n : 입력받을 수 있는 문자열의 최대 길이 전달restrict stream : 문자열을 입력받을 스트림 전달C언어에서 문자열을 출력할 때에는 puts()나 fputs()를 사용한다.
puts()는 표준 출력 스트림(stdout)인 모니터에 하나의 문자열을 출력하는 함수로, 모니터에 문자열을 출력한 다음 자동으로 줄바꿈을 해준다.
#include <stdio.h>
int puts(const char *s);
const char *s : 인수로 출력할 문자열을 가리키는 포인터를 전달함fputs()는 모니터뿐만 아니라 파일을 통해서도 문자를 출력(저장)할 수 있는 함수이다. 이는 문자열 출력 후 자동으로 줄을 바꿔주지 않는다.
#include <stdio.h>
int fputs(const char *restrict s, FILE *restrict stream);
const char *restrict s : 출력할 문자열을 가리키는 포인터를 전달함FILE *restrict stream : 문자열을 출력할 스트림을 전달함puts()는 문자열을 출력한 후 자동으로 줄 바꿈을 해주지만, fputs()는 문자열 출력 후 줄 바꿈을 하지 않는다.
#include <stdio.h>
int main(void)
{
char str[100];
fputs("문자열을 입력해 주세요 :\n", stdout);
fgets(str, sizeof(str), stdin);
puts("입력하신 문자열 : ");
puts(str);
fputs("입력하신 문자열 : ", stdout);
fputs(str, stdout);
return 0;
}
C언어에서 문자열은 마지막에 Null문자를 가지는 문자형 배열로 표현되며, 기본 타입에는 포함되지 않아 문자열을 처리하기 위한 다양한 함수를 별도로 사용해야 한다.
인수로 전달된 문자열의 길이를 반환하는 함수이다.
#include <string.h>
size_t strlen(const char *s);
이 때, 문자열 여부를 구분하는 마지막 문자인 널 문자는 문자열의 길이에서 제외된다.
char str[] = "C언어";
printf("문자열의 길이: %d\n", strlen(str)); // 결과 : 7
utf-8 인코딩 환경에서 한글은 한 문자당 3byte로 처리된다.
strcat()과 strncat()함수는 하나의 문자열에 다른 문자열을 연결해주는 함수이다.
#include <string.h>
char *strcat(char *restrict s1, const char *restrict s2);
char *restrict s1 : 기준 문자열const char *restrict s2 : 추가하고자 하는 문자열의 복사본📌 restrict 키워드
: 포인터의 선언에서만 사용할 수 있는 C99부터 추가된 키워드로, 포인터 선언 시 이를 이용하면 컴파일러는 해당 포인터가 가리키는 메모리에 대한 최적화를 실시함

Q. 기준 문자열이 저장된 배열의 공간이 충분하지 않으면 어떻게 될까?
A. 배열을 채우고 남은 문자들이 배열 외부로 흘러넘칠 수 있음 ⇒ 오버플로우(overflow)
오버플로우 방지를 위해서는 strcat()대신 strncat()을 쓰는 것이 좋다.
strncat()은 추가할 문자열의 최대 길이를 지정할 수 있는 3번째 인수가 있기 때문이다. 이는 null문자를 만나거나 추가하는 문자의 개수가 3번째 인수로 전달된 최대 길이에 도달할 때까지 추가를 계속한다.
#include <string.h>
char *strncat(char * restrict s1, const char * restrict s2, size_t n);
char str01[20] = "C language is "; // 널 문자를 포함하여 15문자
char str02[] = "Cool! and funny!";
//strcat(str01, str02); // 이 부분을 실행시키면 배열 오버플로우 발생
strncat(str01, str02, 5); // 최대 길이를 설정해 놓으면 오버플로우가 발생하지 않음
puts(str01);
Q. strncat()에서 3번째 인수로 5가 들어간 이유?
A. 원래 null문자를 포함한 총 14byte의 문자열을 19byte의 배열에 저장한다. 이후 이 문자열에 5byte 크기의 문자열을 추가해줌으로써 19byte를 맞추어 준 것이다.
strcpy(), strncpy()는 문자열을 복사하는 함수이다.
#include <string.h>
char *strcpy(char * restrict s1, const char * restrict s2);
char * restrict s1 : 첫 번째 인수로 전달된 배열에const char * restrict s2 : 두 번째 인수로 전달된 문자열을 복사함만약 첫 번째 인수로 전달된 배열의 크기 < 복사할 문자열의 길이 이면 배열 오버플로우가 발생한다. 이를 방지하기 위해 strncpy()를 사용한다.

strncpy()도 위의 strncat()처럼 세 번째 인수가 추가된 것이다. 이 세 번째 인수에 복사할 문자열의 최대 길이를 지정해줄 수 있다. strncpy()는 null문자를 만나거나, 복사하는 문자의 개수가 3번째 인수로 전달된 최대 길이에 도달할 때까지 계속 복사한다.
#include <string.h>
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
포인터 연산을 이용하면 수정을 시작할 지점을 지정할 수 있다.
char str01[20] = "C is Cool!";
char str02[11];
// str02 배열의 크기만큼만 복사를 진행하며, 마지막 한 문자는 널 문자를 위한 것임
strncpy(str02, str01, sizeof(str02)-1);
str02[sizeof(str02)-1] = '\0'; // 이 부분을 주석 처리하면, 맨 마지막에 널 문자를 삽입하지 않음
puts(str02);
// --------------------------------
char str[20] = "C is cool!";
strncpy(str+5, "nice", 4); // 배열 이름을 이용한 포인터 연산으로 수정할 부분의 시작 부분을 지정함
puts(str);
strcmp()와 strncmp()는 문자열의 내용을 비교하는 함수이다.
strcmp()는 인수로 두 개의 문자열 포인터를 전달받아, 해당 포인터가 가리키는 문자열의 내용을 서로 비교한다. 두 문자열의 모든 문자는 아스키 코드값으로 자동 변환되며, 문자열의 맨 앞에서부터 순서대로 비교된다.
#include <string.h>
int strcmp(const char *s1, const char *s2);
strcmp()의 상황별 반환값
- 반환값이
양수:첫 번째 인수로 전달된 문자열>두 번째 인수로 전달된 문자열- 반환값이
0: 두 문자열의 내용이 완전히 같은 경우- 반환값이
음수:첫 번째 인수로 전달된 문자열<두 번째 인수로 전달된 문자열
strncmp()도 세 번째 인수에 비교할 문자의 개수를 지정할 수 있다. 이는 일치하지 않는 문자를 만나거나 세 번째 인수로 전달된 문자의 개수만큼 비교를 계속한다.
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[20];
char ch;
while (1)
{
puts("미국의 수도를 입력하세요 :");
scanf("%s", str);
if (strcmp(str, "워싱턴") == 0 || strcmp(str, "washington") == 0) // 문자열의 비교
{
puts("정답입니다!");
break;
}else {
puts("아쉽네요~"); }
fflush(stdin);
puts("\n이 프로그램을 끝내고자 한다면 'q'를 눌러주세요!");
puts("계속 도전하고자 하시면 Enter를 눌러주세요!");
scanf("%c", &ch);
if (ch == 'q') // 문자의 비교
{
break;
}
fflush(stdin);
}
return 0;
}
strcmp() 함수는 문자열을 비교하는 함수이므로, 문자를 비교할 때에는 관계연산자 '=='를 사용해야 한다.
이 함수들은 인수로 전달된 문자열을 해당 타입의 숫자로 변환시켜주는 함수이다.
#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형 실수로 변환
이 함수들은 인수로 전달된 문자열의 영문자를 모두 대문자 or 소문자로 변환시켜주는 함수이다.
#include <ctype.h>
int toupper(int c); // 문자열의 모든 영문자를 대문자로 변환
int tolower(int c); // 문자열의 모든 영문자를 소문자로 변환
Reference
1. 문자열
2. 문자열 입출력 함수
3. 문자열 처리 함수