[C언어] 문자열 활용하기
[C언어] 문자열 활용하기
1. 문자와 문자열
C언어에서 문자와 문자열은 다른 자료 구조이다.
- 문자(character) : ‘a’, ‘b’, ‘$’ ‘@’ 등과 같은 단일의 기호를 말한다. 작은따옴표 안에 기호를 쓴다. 정수나 실수 데이터도 작은따옴표 안에 있으면 문자로 인식된다. ‘13’은 문자 처리가 되지 않아 오류가 생길 수 있다.
- 문자열(String) : “nice”, “안녕” 등과 같이 두 개 이상의 문자 결합 구조를 가진다. 큰따옴표 안에 기호를 쓴다.
1) 문자의 선언 방법
C언어의 문자 자료형은 메모리 한 칸에 하나의 문자만 삽입될 수 있다.
char 변수명 = '변수값';
메모리 안에 변수의 값이 들어가게 된다.
2) 문자열의 선언 방법
메모리 한 칸에 하나의 문자만 들어갈 수 있기 때문에, 문자열을 만들려면 메모리를 여러 개 이어서 붙여야 한다. 메모리가 여러 개 이어진 구조를 배열이라고 부른다.
(1) 배열로 문자열을 선언하는 방법
문자열을 약식으로 설정하는 방법은 다음과 같다.
char 변수명[문자 개수 + 1] = "변수값";
//ex. char a[5] = "find";
문자를 4개 저장하려는데 왜 문자 개수를 + 1 해서 선언을 할까?
C언어는 문자열의 끝을 ‘\0’ 즉 null 값으로 인식해서 끝내기 때문이다.
위의 char a의 경우, {’f’, ‘i’, ‘n’, ‘d’, ‘\0’} 이 들어가 있는 구조처럼 되어 있다고 생각하면 되겠다.
(2) 포인터로 문자열을 선언하는 방법
char* string = "helloWorld";
라고 하는 문자열을 가리키는 string이라는 포인터변수가 있다. 이 포인터변수는 h의 주소값을 가리킨다.
포인터 변수 string은 h의 주소를 가리키므로, string을 출력하면 ‘h’가 출력되고, (string + 1)으로 출력하면 그 뒤에 있는 문자인 ‘e’가 출력되게 된다.
단, “helloWorld” 전체는 ‘상수형’으로 할당되었기 때문에 임의로 배열을 ‘변경할 수 없다.’
(배열로 선언된 문자열의 경우에는 수정이 가능하다.)
한편, 여기에서 string은 포인터 변수라고 하기도 하지만, ‘문자열 상수’라고도 한다.
(3) 문자열로 포인터 선언 할 때 일어나는 일
char* arr1 = “abc”; //4바이트짜리 문자 배열
char* arr2 = “abc”; //4바이트짜리 문자 배열
이렇게 만든다고 하자. C언어에서는 메모리를 절약하기 위해 이 값을 코드영역에 저장하고, 그 값을 공유(재활용)한다. 만약, arr2가 “abcd”가 된다고 하면, 메모리 주소값이 서로 달라지는 것을 볼 수 있다.
이 때 주소값은 4차이가 나는데, 0~2까지는 a,b,c 각각 문자가, 3은 null이 차지하고 있어서 그렇다.
여기에 덧붙여서 char* arr3 = “bc”;를 선언하는 경우, arr1과 주소값 차이가 1이 나는데, b부터 c까지의 값과 똑같은 것을 사용하기 때문에, 그 주소를 그대로 쓰는 것이다. (메모리 절약의 차원)
(4) %s 사용하지 않고 문자열 출력하기
// 문장을 출력하는 함수(print_str)를 만들어주세요.(%s 사용 금지)
// 조건 : %s를 사용할 수 없다.
#include <stdio.h>
#define true 1
void print_str(char* str) {
printf("== print_str ==\n");
for ( int i = 0; *(str + i) != '\0'; i++ ) {
printf("%c", *(str + i));
}
printf("\n");
}
int main(void) {
char str1[10];
str1[0] = 'a';
str1[1] = 'b';
str1[2] = 'c';
str1[3] = '\0';
// print_str 함수를 활용하여 문장 str1 출력 실행
print_str(str1); // print_str(&str1[0]); 와 같다.
// 출력 => abc
char str2[10];
str2[0] = 'h';
str2[1] = 'e';
str2[2] = 'l';
str2[3] = 'l';
str2[4] = 'o';
str2[5] = ' ';
str2[6] = 'c';
str2[7] = '\0';
// print_str 함수를 활용하여 문장 str2 출력 실행
print_str(&str2[0]); // print_str(str2);
// 출력 => hello c
return 0;
}
3. 0 또는 Null 활용하기
포인터와 마지막을 알리는 0 또는 null을 활용하면 문자의 길이값, 특정 문자의 위치, 배열 내에 문자가 있는지 확인할 수 있다. 또한 슬라이싱도 가능하다.
여러 가지의 0 또는 null이 쓰이는데, 정리해보면 다음과 같다.
'\0' : 문자로서의 0
0 : 숫자로서의 0
NULL : 포인터로서의 0
1) 문자열의 길이값 반환하기
아래와 같이 '\0'을 활용하면 문자의 길이값을 반환하여 입출력과 같은 것에 활용할 수 있다.
int get_str_len(char* name){
int i = 0;
while(1){
if (*(name + i) != '\0'){ //or name[i]
i++;
continue;
}else{
return i;
}
}
}
int main(void) {
char name[100] = "Paul"; // 이렇게 하면 name이 가리키는 배열에 Paul이 저장되면서 시작된다.
int len = get_str_len(name);
printf("len : %d\n", len);
// 출력 => len : 4
name[0] = 't';
name[1] = 'o';
name[2] = 'm';
name[3] = 'a';
name[4] = 's';
name[5] = '\0';
len = get_str_len(name);
printf("len : %d\n", len);
// 출력 => len : 5
return 0;
}
2) 특정 문자의 위치를 반환하는 함수 구현하기
0을 활용해서 그 문자열 안에 특정 문자가 어디에 있는 지를 반환하는 함수도 만들 수 있다.
// 문제 : 문장에서 특정 문자의 위치를 반환하는 함수를 만들어주세요.(get_index_of_c)
#include <stdio.h>
int get_index_of_c(char* a, char b){
int len = 0;
while ( *a != b) {
a++;
len++;
if (*a == '\0'){
return -1;
}
}
return len;
}
int main(void) {
int index;
index = get_index_of_c("abc", 'b');
printf("index : %d\n", index);
// 출력 => index : 1
index = get_index_of_c("test", 's');
printf("index : %d\n", index);
// 출력 => index : 2
index = get_index_of_c("test", 'x');
printf("index : %d\n", index);
// 출력 => index : -1
return 0;
}
3) 주어진 문자열이 배열 내에 있는지 확인하기.
동일한 문자열이 배열 안에 있는지도 확인할 수 있다.
// 문제 : 주어진 문자열이 배열 내에 있는지 확인하기.
#include <stdio.h>
int get_index_of(char* a, char* b){
char first_a = a[0];
char first_b = b[0];
for(int i = 0; *(a + i) != '\\0'; i++){
if(a[i] == b[0]){
int k = 0;
for(int j = i; *(b + k) != '\\0'; j++){
if(a[j] == b[k]){
k++;
continue;
}else if(a[j] != b[k]){
return -1;
}else{
return -1;
}
}
return i;
}
}
return -1;
}
int main(void) {
printf("%d\\n", get_index_of("abcd", "b")); // 1
printf("%d\\n", get_index_of("abcd", "bc")); // 1
printf("%d\\n", get_index_of("abcd", "bcd")); // 1
printf("%d\\n", get_index_of("abcd", "bd")); // -1
printf("%d\\n", get_index_of("abcd", "abcd")); // 0
printf("%d\\n", get_index_of("abcd", "d")); // 3
return 0;
}
4) 문장에서 특정 부분만 잘라서 출력하기(Slicing)
python이나 java에서만 가능할 것 같았던 slicing도 가능하다.
// 문제 : 문장에서 특정 부분만 잘라서 출력하는 함수를 만들어주세요.(print_sub_str)
#include <stdio.h>
void print_sub_str(char* str, int start, int end){
for(int i = start; i < start + end; i++){
if ( str[i] == '\\0' ) {
break;
}
printf("%c", str[i]);
}
printf("\\n");
}
int main(void) {
print_sub_str("abcd", 2, 2);
// 출력 => cd
print_sub_str("abcd", 1, 3);
// 출력 => bcd
print_sub_str("abcd", 1, 10);
// 출력 => bcd
print_sub_str("abcd", 0, 2);
// 출력 => ab
return 0;
}