문자열
여태까지 문자열을 저장하기 위해 cs50 라이브러리에 포함된 string 자료형을 사용하였음
string s = "EMMA";
문자열은 결국 문자의 배열이고, s[0], s[1], s[2], s[3]와 같이 하나의 문자가 배열의 한 부분을 나타냄
마지막의 \0은 0으로 이루어진 바이트(1바이트)로, 문자열의 끝을 표시하는 약속(널 종단 문자)
여기서 변수 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
'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 |