Taking baby-developer steps
11. 문자열 - 문자열의 개념 / 널(NULL)값 / 문자열과 포인터 / 문자열 리터럴 / 문자열 입출력 함수 / gets () 함수 /gets_s() 함수 / sizeof()함수 / 문자열 처리 함수 본문
11. 문자열 - 문자열의 개념 / 널(NULL)값 / 문자열과 포인터 / 문자열 리터럴 / 문자열 입출력 함수 / gets () 함수 /gets_s() 함수 / sizeof()함수 / 문자열 처리 함수
Surin Lee 2021. 3. 25. 14:16문자열
전통적인 C언어에서 문자열을 다루는 방법과 다양한 문자열 관련 함수를 익히고 활용한다.
문자열의 개념
문자열이란 말 그대로 문자들의 배열이다. 문자열은 컴퓨터 메모리 구조상에서 마지막에 널(NULL)값을 포함한다. 컴퓨터에서 널(NULL)이란, '존재하지 않는다'라는 뜻으로, 즉 어떠한 값도 의미있는 값이 들어가 있지 않음을 의미한다. 이 널(NULL)값은 '\0'이라는 문자 형태로도 표현한다.
0 | 1 | 2 | 3 | 4 | 5 |
H | E | L | L | O | \0 |
위의 문자열은 총 5개의 문자와 NULL값으로 이루어져 있다.
널값은 문자열의 끝을 알리는 목적으로 사용된다. printf() 함수를 실행하면 컴퓨터는 내부적으로 NULL을 만날 때 까지 출력한다. 이처럼 NULL값은 문자를 처리 할 때 중요한 요소로 사용된다.
문자열과 포인터
문자열 형태로 포인터를 사용하면 포인터에 특정한 문자열의 주소를 넣게 된다.
#include <stdio.h>
int main(void){
char *a = "Hello World";
printf("%s\n", a);
return 0;
}
위의 코드는 "Hello World"라는 문자열을 읽기 전용으로 메모리 공간에 넣은 뒤에 그 위치를 처리한다. 위의 코드에서
char *a = "Hello World" ;
처럼 포인터 변수에 '문자열 자체'를 마치 상수처럼 넣을 수 있는데, 이런 문자열 자체를 '문자열 리터럴'이라고 한다. 이렇게 문자열 리터럴 형태로 쓰면, 컴파일러가 알아서 "Hello World"라는 문자열이 특정한 컴퓨터 메모리 주소에 담길 수 있도록 알아서 남아있는 메모리 공간 중 '주소'를 결정 해주며, 이 주소를 포인터가 가지게 된다.
이렇게 문자열 리터럴 방식으로 선언을 해주면, 이 문자를 자체는 상수로서 '읽기 전용'으로 사용이 된다. (즉, 변경이 불가능 해진다.)
+ 굳이 문자열을 변경해서 사용하고 싶다면, 포인터 a가 가리키고 있는 주소를 바꾸어(다른 주소를 가리키게 한 후) 사용해야 한다.
포인터로 문자열을 선언 했을 때, 기존의 배열 처럼 처리할 수 있다.
#include <stdio.h>
int main(void){
char *a = "Hello World";
printf("%s\n", a[1]);
printf("%s\n", a[4]);
printf("%s\n", a[8]);
return 0;
}
-> e o r (각각 줄 바꿔서 출력 됨)
기존의 배열 처럼 각 인덱스에 해당하는 값이 출력되는 것을 확인 할 수 있다. 배열과 포인터는 치환이 가능하므로, Printf()함수 내에서 주소 연산자 &없이 쓰인것을 볼 수 있다.
문자열 입출력 함수
gets() 함수 / gets_s() 함수
scanf() 함수는 공백을 만날 때까지 입력 받지만, gets() 함수는 공백까지 포함하여 한 줄을 입력 받는다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void){
char a[100];
gets(a) ;
printf("%s\n",a);
return 0;
}
gets() 함수는 버퍼의 크기를 벗어나도 입력을 받아버린다는 취약점이 있다. (배열의 전체 범위를 고려하지 않는다는 점에서, 보안상의 취약점이 있다. 공부하는 입장으로 gets()가 더 이해가 쉬우므로, _CRT_SECURE_NO_WARNINGS를 쓰고, 사용한다. 실무에선 gets_s()를 사용한다.) gets()함수가 버퍼의 크기를 벗어나도 입력을 받아버리면, 입력하는 사용자가 프로그램의 다른 부분을 임의대로 덮어쓰기 할 수도 있다는 취약점이 생긴다.
이런 취약점을 보안하기 위해, C11 표준부터는 버퍼의 크기를 철저히 지키는 gets_s()함수가 추가 되었다. gets_s()함수는 매개변수를 2개를 받고, 특정한 범위 만큼만 정확히 문자를 입력 받아 다소 안정적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void){
char a[100];
gets_s(a,sizeof(a));
printf("%s\n",a);
}
-> 입력 값으로 버퍼의 크기(100자)를 벗어나게 되면, 오류메세지가 뜨면서 프로그램이 종료된다.
gets_s()를 이용하는 경우, 입력 범위를 넘으면 그 즉시 런타임(Runtime) 오류가 발생한다.
+ sizeof() 함수
C언어에서 기본적으로 제공하는 함수로서, 특정한 배열의 "전체 크기가 얼마인지"를 알려주는 함수 이다.
문자열 처리를 위한 다양한 함수
C언어에서의 문자열 함수는 <string.h> 라이브러리에 포함되어 있다. C언어의 문자열 처리와 관련한 기본적인 문자열 함수를 알고 있는 것이 좋다. 후에 C++을 이용하면 더욱 간편하고 다양한 함수를 사용 할 수 있다.
strlen() / srtlen(a) | 문자열의 길이를 반환한다. |
strcmp() / strcmp(a, b) | 문자열 1이 문자열 2보다 사전적으로 앞에 있으면 -1, 뒤에 있으면 1을 반환한다. |
strcpy() / strcpy(a, b) | 문자열을 복사한다. |
strcat() / strcat(a, b) | 문자열 1에 문자열 2를 더한다. (이어서 작성한다.) |
strstr() / strstr(a, b) | 문자열 1에 문자열 2가 어떻게 포함되어 있는지를 반환한다. |
+전통적인 C언어에서는 위의 함수들을 이용하려면, #include <string.h>를 써야하지만, 최근 C언어는 문자열 함수를 기본적으로 포함하는 경우가 많아, 써주지 않아도 제대로 동작한다.
strcat()에서 합쳐지는 배열의 크기가 부족하면, 다양한 오류가 발생 할 수 있으므로 늘려주는게 좋다.
strstr()은 긴 문자열에서 짧은 문자열을 찾아 그 위치를 반환한다. 짧은 문자열을 찾은 주소 값 자체를 반환하므로, 단순히 출력하도록 하면 찾은 이후 모든 문자열이 반환된다.
#include <stdio.h>
int main (void){
char a[20] = "I like you";
char b[20] = "like" ;
printf("찾은 문자열 : %s\n", strstr(a, b));
return 0;
}
-> like you
요약
- C언어에서 문자열은 배열이므로 포인터 형태로 사용할 수 있다.
- C언어에서 문자열 비교, 연산, 탐색 등의 알고리즘의 사용 방법은 각각 함수 형태로 제공 된다.
'CS 지식 > C언어_basic' 카테고리의 다른 글
13. 다차원 배열과 포인터 배열 - 2차원 배열(필요성, 초기화,모든 원소 출력하기) / 다차원 배열 /배열과 포인터의 구조 분석 (0) | 2021.03.26 |
---|---|
12. 컴퓨터가 변수를 처리하는 방법 - 프로그램 메모리 주소/전역 변수 / 지역 변수 / 정적 변수 / 레지스터 변수 /함수의 매개변수 처리(값에 의한 전달 / 참조에 의한 전달) (0) | 2021.03.26 |
10. 문자 - 아스키 코드 / 문자 입출력 함수 / 문자와 버퍼 (0) | 2021.03.25 |
9. 포인터 - 포인터의 개념 / 포인터 관련 연산자(주소연산자, 포인터, 간접 참조 연산자) / 포인터의 기능 (0) | 2021.03.24 |
8. 배열 - 배열의 선언과 초기화 / INT_MIN / 문자열과 배열 (0) | 2021.03.19 |