카테고리 없음

[c언어] 문자열

제이G 2023. 6. 19. 15:11

문자열 기본 개념

- 문자들의 배열을 의미한다. 정확히는 널종단문자(\0)까지를 포함한 문자들의 배열.

- 문자열을 가리키는 변수는 포인터이고, 문자열의 첫 번째 주소를 가리킨다.

#include <stdio.h>

int main(void)
{
	//string is actually char array
	//name pointer has char array's first address
	//so, name is just address
	char *name = "EMMA";
	printf("%s\n", name);
	printf("EMMA's(char array) address: %p\n", name);
	printf("EMMA's first char address: %p\n", &name[0]);
	printf("EMMA's second char address: %p\n", &name[1]);
	printf("EMMA's third char address: %p\n", &name[2]);
}


문자열 메모리 그림으로 표현

  • string의 크기는 다른 변수처럼 정해져있지 않다.
  • 따라서, string이 언제 끝나는지 알아야할 것이다.
  • 이를 알려주기 위한 것이 null문자 (\0)이다. 즉,
  • string의 변수명 → 문자열의 시작위치 (포인터)
  • \\0 → 문자열의 끝위치
  • 문자열의 크기: 글자수 + 1 byte
  • null문자 (\0)는 이진수로 0000 0000을 의미함.
  • 문자 ‘0’은 아스키 코드 값으로 48이다.

문자열 구현 방식

1. String Literal(문자열 상수)

char 포인터 = "문자열"; 

char *s = "EMMA";
  • char 포인터로 선언하면 문자배열이고, 상수이다. 해당 문자열 상수 "EMMA"는 메모리의 읽기전용 영역에 저장된다.
  • 따라서, s[0] = 'A'와 같이 수정이 불가(segmentation fault)하다.
  • ※ 포인터는 수정가능 여부와 연관이 없다. 단지, 위와 같이 구현한 상수문자열은 메모리의 읽기전용 영역에 생성되고, 포인터 s는 읽기전용 영역을 가리키고 있으므로, 수정이 불가한 것이다. (페이지 테이블의 수정가능 bit를 보고 판단)
  • 변수 s는 "EMMA"배열의 첫번째 주소를 저장하고 있는 포인터이다.

 

2. char array(문자 배열)

char 변수명[] = "문자열";

char s[] = "EMMA";
  • char 배열로 선언하면 문자 배열이다. 해당 문자열 "EMMA"는 메모리의 읽기쓰기 영역에 저장된다.
  • 따라서, s[0] = 'A'와 같이 수정이 가능하다.
  • 변수 s는 "EMMA" 배열의 첫번째 주소를 저장하고 있는 포인터이다.

즉, 위 두 방법은 문자열을 상수로 선언할 것인지, 문자 배열로 선언할 것인지 구현 방법의 차이인 것이고,

이에 따라, 메모리의 읽기전용 영역에 저장하는지, 메모리의 읽기쓰기 영역에 저장하는지의 차이가 발생하는 것이다.

※ s는 모두 포인터이다.

 

※ 두 방법 모두 근본적으로는 포인터이지만, 선언한 타입은 엄연히 다르기 때문에 타입을 잘 고려해야 한다.

아래와 같이 return type: void *인 malloc을 char[] 타입 t로 받는다면 type 오류가 발생한다.

 

 


문자열 접근

code example1

#include <stdio.h>

int main(void)
{
    char *s = "EMMA";

    printf("%p\n", s);  //print: EMMA
//  printf("%p\n", *s); //compile error
    printf("%c", *s);   // print: E
    printf("%c", *(s+1));   // print: M
    printf("%c", *(s+2));   // print: M
    printf("%c\n", *(s+3)); // print: A

    printf("%c\n", *s + 2); // print: E + 1 -> F

    //use bracket
    //if use bracket, compiler automatically convert to above case
    printf("%c", s[0]); //print: E
    printf("%c", s[1]);   //print: M
    printf("%c", s[2]);   //print: M
    printf("%c\n", s[3]);   //print: A  
}

 

code example2

/*
descrption:
An Example of two ways to represent a string(char array).
*/

#include <stdio.h>

int main(void)
{

    char *s = "JONADAN";
    char m[] = "EMMA";

    printf("%s\n", s);
    printf("%s\n", m);

    printf("char array(string literal) print\n");
    printf("%c%c%c%c\n", s[0], s[1], s[2], s[3]);
    printf("%c%c%c%c\n", *s, *(s+1), *(s+2), *(s+3));

    printf("char array print\n");
    printf("%c%c%c%c\n", m[0], m[1], m[2], m[3]);
    printf("%c%c%c%c\n", *m, *(m+1), *(m+2), *(m+3));
}

  • 문자열을 저장하는 char 포인터 변수 s는 문자열의 첫번째 주소를 저장하고 있다.
  • char m[]는 문자열 배열로 선언한 것이고, char *s  문자열 상수로 선언한 것이다.
  • 즉, 근본적으로 m, s는 문자열 배열의 첫번째 주소값을 저장하고 있는 포인터이다.
    ※ 선언한 타입 자체는 다르기 때문에, 타입을 잘 맞춰줘야 한다.
  • 즉 두 방법 모두, *(s+i)로 원하는 문자에 접근할 수 있다.
  • s[i]를 통해 원하는 문자에 접근하는 경우는 컴파일러가 자동으로 *(s+i) 형태로 변환해주고 있는 것이다.

 

 

 


문자열 비교

#include <stdio.h>

int main(void) {
    char *s1 = "ABC";   // char array(String Literal) 
    char *s2 = "ABC";   // char array(String Literal)

    char s3[] = "SS";   // char array
    char s4[] = "SS";   // char array

    // result: Same
    // if each String Literal is same, each pointer is same by compiler's optimization.
    printf("s1: %p, s2: %p\n", s1, s2);
    if(s1 == s2) {
        printf("s1 and s2 is Same\n");
    } else {
        printf("s1 and s2 is Difference\n");
    }

    // result: Difference
    // each char array "SS" is stored at difference memory area,
    // So each pointer is difference.
    printf("s3: %p, s5: %p\n", s3, s4);
    if(s3 == s4) {
        printf("s3 and s4 is Same\n");
    } else {
        printf("s3 and s4 is Difference\n");
    }
}

 

char s[] = "EMMA", char t[] = "EMMA" example

  • 문자열을 표현하는 방법은 두 가지이다.
  • 첫째, char *s = "EMMA"; // char array(String Literal)
  • 둘째, char s[] = "EMMA"; // char array
  • 문자열 상수의 경우, 읽기 전용 메모리 공간에 할당되고, 같은 문자열인 경우(EMMA, EMMA) 동일한 메모리 공간이다.
  • char array의 경우, 읽기 쓰기 메모리 공간에 매번 할당된다. 즉, 서로 다른 메모리 공간이다. 

 


문자열 수정

 

  • 첫번째 방법인 String Literal은 읽기 전용 메모리 공간에 할당된다.
  • 두번째 방법인 char array는 읽기-쓰기 메모리 공간에 할당된다.
  • 따라서, 

 

 


문자열 복사

#include <stdio.h>
#include <string.h> //for strlen
#include <stdlib.h> //for malloc
#include <ctype.h> //for toupper

int main(void)
{

    char s[] = "emma";

    //malloc: allocate memory
    //param: want byte size
    char *t = malloc(4 + 1);

    // by for-loop  
    for(int i = 0, n = strlen(s); i <= n; i++) {
        t[i] = s[i];
    }

    t[0] = toupper(t[0]);

    printf("%s\n", s);
    printf("%s\n", t);

    char *t2 = malloc(4 + 1);

    // by strcpy(new, old)
    strcpy(t2, s);
    t2[0] = 'A';
    printf("%s\n", t2);
}

 

 

 

 

 

printf 형식 지정자

  • %s: 문자열 전체를 출력 (널 종단문자 만날 때 까지)
  • %c: 문자를 출력
  • %p: 주소값