본문 바로가기
Computer Science

[C언어] 문자열 활용하기

by DuncanKim 2022. 7. 12.
728x90

[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;
}
728x90

'Computer Science' 카테고리의 다른 글

[C언어] C언어 구조체(struct)  (0) 2022.07.13
[C언어] 문자열을 활용한 여러 함수 만들기  (0) 2022.07.13
[CS] 결합도와 응집도  (0) 2022.07.12
[CS] 테스트와 TDD  (0) 2022.07.09
[CS] 객체지향 디자인패턴  (0) 2022.07.07

댓글