본문 바로가기
cs/CS50

5: 메모리-3(문자열, 문자열의 비교와 복사)

by 이쟝 2021. 12. 3.

문자열 

여태까지 문자열을 저장하기 위해 cs50 라이브러리에 포함된 string 자료형을 사용하였음

string s = "EMMA";

문자열은 결국 문자의 배열이고, s[0], s[1], s[2], s[3]와 같이 하나의 문자가 배열의 한 부분을 나타냄

마지막의 \0은 0으로 이루어진 바이트(1바이트)로, 문자열의 끝을 표시하는 약속(널 종단 문자)

 

주소 0x1234

여기서 변수 s는 문자열의 첫 번째 글자를 가리키는 포인터가 됨(주소 0x1234에 있는 s[0]을 가리킴) 그러면 컴퓨터는 널 종단 문자를 마주칠 때까지 루프를 돌면서 끝을 알아냄

결국 문자열은 문자 배열의 첫 번째 바이트 주소가 됨 그리고 마지막 바이트에는 \0을 저장해 끝을 알려줌

 


실제 cs50 라이브러리를 보면 string 자료형은 아래와 같이 저장되어 있음

 

typedef char * string

- typedef: 새로운 자료형을 선언한다는 의미

- char *: 이 값의 형태가 문자의 주소가 될 것이라는 의미

- *는 주소를 나타내고 char는 주소에 있는 값의 자료형이 char이라는 것

- string: 이 자료형의 이름(어떤 char의 주소를 가지고 있는 변수)


1) string 자료형을 이용해 "EMMA를 출력

 

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    string s = "EMMA";
    printf("%s\n", s);
}

 

2) char 포인터를 이용해 "EMMA"를 출력

 

#include <stdio.h>

int main(void)
{
    char *s = "EMMA";
    printf("%s\n", s);
}

 

string s = "EMMA"; → char *s = "EMMA"; 결과는 똑같이 EMMA!

 

#include <stdio.h>

int main(void)
{
    char *s = "EMMA";
    printf("%s\n", s);     //EMMA
    printf("%p\n", s);     //0x42ae7a
    printf("%p\n", &s[0]); //0x42ae7a
    printf("%p\n", &s[1]); //0x42ae7b
    printf("%p\n", &s[2]); //0x42ae7c
    printf("%p\n", &s[3]); //0x42ae7d

 

 

s라는 변수는 문자에 대한 포인터가 되고 “EMMA”라는 가장 첫 번째 값을 저장하기 때문에 2번째 printf랑 3번째 printf랑 같은 것을 볼 수 있음

&s[0]은 “E”의 주소 값을, &s[1]은 “M”의 주소 값을, &s[2]는 “M”의 주소 값을, &s[3]은 “A”의 주소 값을 의미함

문자열은 첫 번째 문자를 시작으로 메모리상에서 바로 옆에 저장되어 있음


가장 첫 번째 문자에 해당하는 주소 값을 하나씩 증가시키면 바로 옆에 있는 문자의 값을 출력할 수 있음

 

#include <stdio.h>

int main(void)
{
   char *s = "EMMA";
   printf("%c\n", *s);      //E
   printf("%c\n", *(s+1));  //M
   printf("%c\n", *(s+2));  //M
   printf("%c\n", *(s+3));  //A
}

 


문자열의 비교

문자열을 비교할 때도 아래 코드와 같이 문자열이 저장된 변수를 바로 비교하기 되면 그 변수가 저장되어 있는 주소가 다르기 때문에 다르다는 결과가 나옴

 

#include <stdio.h>
#include <cs50.h>

int main(void)
{
    //사용자로부터 s와 n 두 개의 문자열을 입력받아 저장
    string s = get_string("s: ");
    string n = get_string("n: ");

    //두 문자열을 비교(각 문자들을 비교)
    if(s == n)
    {
        printf("Same\n");
    }
    else
    {
        printf("Different\n");
    } 
}

 

결과

같은 문자열을 입력해도 Same이 출력되지 않음

get_string으로 문자열을 입력받아 s라 하고 또 다른 문자열을 받아 n이라 하면 메모리 두 덩어리를 얻게 되는 것이고 사용자가 동일한 문자열을 입력해도 같은 곳에 있다는 의미는 아님

그래서 첫 번째 변수 s의 EMMA와 두 번째 변수 n의 EMMA는 각각 다른 주소에 있음

정확한 비교를 위해서는 실제 문자열이 저장되어 있는 곳으로 이동해, 각 문자를 하나씩 비교해야 함


문자열 복사

 

입력 받은 문자열을 복사해서 대문자로 바꾸는 코드 작성

 

#include <stdio.h>
#include <cs50.h>  //for get_string
#include <ctype.h> //for toupper

int main(void)
{
   string s = get_string("s: "); //사용자에게 입력값을 받아서 s에넣기
   string t = s;  //입력값s을 t에 복사

   t[0]=toupper(t[0]);  //t의 첫 번째 문자를 대문자로 바꾸기

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

 

- 입력값으로 "emma"를 주게 되면, s와 t 모두 "Emma"로 출력됨

- s라는 변수에는 "emma"라는 문자열이 아닌 그 문자열이 있는 메모리의 주소가 저장되기 때문(string s == char *s)

- 따라서 t도 s와 동일한 주소를 가리키고 있고, t를 통한 수정은 s에도 그대로 반영됨

- 두 문자열을 실제로 메모리상에서 복사하려면? → 메모리 할당 함수를 사용

- 메모리를 추가로 사용해서 EMMA와 동일한 크기의 변수를 만들고 s 안에 있는 글자를 하나씩 t로 복사하기


메모리 할당 함수(malloc)

- 인자로 받는 것은 할당 받을 메모리 크기(정해진 크기 만큼 메모리를 할당함)

- malloc을 사용해서 EMMA를 복사하는데 필요한 메모리 공간을 할당 받고 for루프를 통해 실제로 복사를 하게 됨

 

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

int main(void)
{
    char *s = get_string("s: "); //사용자에게 입력값을 받아서 s에넣기
   
    char *t = malloc(strlen(s)+1);  //입력받는 문자열의 수 + 널 종단문자

    for (int i = 0, n = strlen(s); i < n + 1; i++) //널종단문자까지 더하기
    {
        t[i] = s[i];  // s값을 t에 복사
    }
    
    t[0] = toupper(t[0]);
    printf("%s\n",s);
    printf("%s\n",t);
}

 

위 코드와 다른 점은 malloc이라는 함수를 이용해서 t를 정의하는 것

즉 s의 문자열의 길이(EMMA:4)에 \0에 해당하는 1을 더한 만큼 메모리를 할당함(total 5)

그리고 루프를 돌면서 s 문자열 배열에 있는 문자 하나 하나를 t 배열에 복사해주면 됨

 

결과

https://www.boostcourse.org/cs112/joinLectures/41307

 

모두를 위한 컴퓨터 과학 (CS50 2019)

부스트코스 무료 강의

www.boostcourse.org

 

 

'cs > CS50' 카테고리의 다른 글

5: 메모리-5(메모리 교환, 스택,힙)  (0) 2021.12.04
5: 메모리-4(메모리 할당과 해제)  (0) 2021.12.03
5: 메모리-2(포인터)  (0) 2021.12.02
5: 메모리-1(메모리 주소)  (0) 2021.12.02
4: 알고리즘-8(병합 정렬:Merge sort)  (0) 2021.12.01