yon11b

여러가지 문자열 표현 본문

언어/C

여러가지 문자열 표현

yon11b 2021. 12. 24. 02:46
반응형

4가지 방법으로 문자열을 표현하는 방법을 알아보자.

 

1. 1차원 문자 배열을 여러 개 사용

char num0[5]="zero";
char num1[5]="one";
char num2[5]="two";

printf("%s\n",num0);
printf("%s\n",num1);
printf("%s\n",num2);

\0는 문자열의 끝을 나타내는 기호로, 위 코드와 같이 문자열을 초기화할때는 자동으로 생성된다.

문자열을 프린트할 때는 출력하고자 하는 문자열이 담겨 있는 배열이름만을 쓰면 된다.

printf("%s\n",num0);
printf("%s\n",num1);
printf("%s\n",num2);

배열 이름은 배열의 첫 번째 원소의 주소를 가리킨다.

num0='z'의 주소

따라서 여기서 배열 이름의 자료형은 char*이다.

하지만 이렇게 문자열 하나에 배열 하나씩 새로 생성해서 할당하면 복잡하기도 하고 불편하다.

그래서 우리는 2차원 문자 배열을 이용할 것이다.

2. 2차원 문자 배열을 사용

2차원 문자 배열은 다수의 문자열 처리에 특화되었다.

char num[3][5]={"zero","one","two"};
for (int i=0;i<3;i++)
	printf("%s\n",num[i]);

역시나 여기서도 문자열을 프린트할 때는 출력하고자 하는 문자열이 담겨 있는 배열이름만을 쓰면 된다.

zero라는 문자열이 담겨있는 배열이름은 num[0]니까 num[0]만 써주면 된다.

num[0], num[1],num[2]의 자료형은 char* 이다.

3. 문자형 포인터를 여러 개 사용

1번과 다른 점은 1번은 문자를 수정할 수 있지만

포인터를 사용하게 되면 상수 영역이 되기 때문에 변경이 불가능하다는 점이다.

char *pnum0="zero";
char *pnum1="one";
char *pnum2="two";

printf("%s\n",pnum0);
printf("%s\n",pnum1);
printf("%s\n",pnum2);

여기서 궁금증!

1번 방법이 있는데 왜 굳이 포인터를 사용하는가?

1번 방법으로 하면 선언을 할 때마다 배열 크기를 정해줘야 한다.

char num[5]="zero";

이렇게.

근데 포인터로 선언하면 배열 크기를 정해주지 않아도 선언이 된다.

그러니까 우리는 배열 크기를 모르지만 배열 선언은 해야 할 때 포인터를 사용하여 선언을 해주면 된다!

4. 문자형 포인터 배열 (포인터들을 배열로 묶기)

char *pnum[3]={"zero", "one", "two"};
for (int i=0;i<3;i++)
	printf("%s\n",pnum[i]);

문자열을 프린트할 때는 출력하고자 하는 문자열이 담겨 있는 배열이름만을 쓰면 된다.

여기서도 역시 *pnum[i]가 아니라 pnum[i]이다 왜냐하면 pnum[i]이 문자열을 담고 있기 때문이다

3번 코드에서는 pnum0[0]가 'z'라는 문자 하나를 가리켰는데 여기서는 pnum[0]이 문자 하나가 아니라 "zero"라는 문자열을 가리킨다!! 이 점이 다르다는 것을 잘 인지하면 *을 언제 써야 하는지 이해할 수 있을 것이다.

 

++추가!!

여기서는 char형 포인터 배열에다가 바로 문자열들을 저장했는데 이렇게 하지 않고 char형 배열에 문자열들이 들어있는 상태에서 char형 포인터 배열이 이 문자열들을 가리키게 할 수도 있다.

#include <stdio.h>
#pragma warning(disable:4996)
int main() {
    char str1[2][6] = { "solar","sido" };
    char* p[2];
    p[0] = str1[0];     // p[0]=str1; 도 가능함!
    p[1] = str1[1];
    puts(p[0]);
    puts(p[1]);
}

여기서는 printf가 아니라 puts 함수를 써봤다.

puts 함수는 문자열 출력함수로, string.h 헤더 파일에 저장되어있다.

int puts(char *str)

str이 가리키는 문자열을 화면에 출력하고 마지막에'\n' 출력한다.

반환 값 : 출력에 성공하면 음수가 아닌 값, 실패하면 EOF 반환.(end of file)

간단히 puts 함수에 대해 적어봤는데 써져있는바와 같이 puts는 포인터형을 인자로 받는다.

그래서 배열이름을 고대로 써준 것이다.

puts(p[0]) 이렇게.

 

 

점검 문제!

아래 문자열로 문자배열 초기화하고

"Time is gold"

"No pain no gain"

"No sweat no sweet"

각 문자열에서 'a'가 몇 번 나오는지 출력하기

1번을 활용하여 코드 작성

더보기
#include <stdio.h>
int main(){
    int cnt = 0;
    char str0[20]={"Time is gold"};
    char str1[20]={"No pain no gain"};
    char str2[20]={"No sweat no sweet"};

    //str0에서 a 개수 찾기
    for (int j = 0; j < 20; j++) {
        if ((str0[j]) == 'a') cnt++;
    }
    printf("%d\n", cnt);

    //str1에서 a 개수 찾기
    cnt = 0;
    for (int j = 0; j < 20; j++) {
        if ((str1[j]) == 'a') cnt++;
    }
    printf("%d\n", cnt);

    //str2에서 a 개수 찾기
    cnt = 0;
    for (int j = 0; j < 20; j++) {
        if ((str2[j]) == 'a') cnt++;
    }
    printf("%d", cnt);
    return 0;
}

2번을 활용하여 코드 작성

더보기
#include <stdio.h>
int main() {
    int cnt = 0;
    char str[3][20] = { "Time is gold","No pain no gain","No sweat no sweet" };

    for (int i = 0; i < 3; i++) {
        cnt = 0;
        for (int j = 0; j < 20; j++) {
            if ((str[i][j]) == 'a') cnt++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

훨씬 깔끔해진다

3번을 활용하여 코드 작성

더보기
#include <stdio.h>
int main() {
    int cnt = 0;
    char *str0 = { "Time is gold" };
    char *str1 = { "No pain no gain" };
    char *str2 = { "No sweat no sweet" };

    //str0에서 a 개수 찾기
    for (int j = 0; j < 20; j++) {
        if ((str0[j]) == 'a') cnt++;
    }
    printf("%d\n", cnt);

    //str1에서 a 개수 찾기
    cnt = 0;
    for (int j = 0; j < 20; j++) {
        if ((str1[j]) == 'a') cnt++;
    }
    printf("%d\n", cnt);

    //str2에서 a 개수 찾기
    cnt = 0;
    for (int j = 0; j < 20; j++) {
        if ((str2[j]) == 'a') cnt++;
    }
    printf("%d", cnt);
    return 0;
}

보면 알겠지만 맨 처음에 배열 선언에서 * 한걸 제외하면 1번과 다른 게 없다.

여기서 우리는 *을 사용해도 나머지 기능은 똑같이 작용한다는 것을 알 수 있고, *은 정말 배열 크기를 지정해주지 않을 때 사용하면 [ ]을 사용한 것과 다를 바가 없다는 것을 알 수 있다.

 

4번을 활용하여 작성한 코드

더보기
#include <stdio.h>
int main() {
    int cnt = 0;
    char *str[3] = { "Time is gold","No pain no gain","No sweat no sweet" };

    for (int i = 0; i < 3; i++) {
        cnt = 0;
        for (int j = 0; j < 20; j++) {
            if ((str[i][j]) == 'a') cnt++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

이것도 *을 제외하면 2번이랑 똑같다.

 

좀 더 발전시켜보자

아래 코드들에서도 [ ]이 아니라 포인터를 사용해보자.

 

4번에서 좀 더 발전된 코드

더보기
#include <stdio.h>
int main() {
    int cnt = 0;
    char* p, * q;
    char *str[3] = { "Time is gold","No pain no gain","No sweat no sweet" };

    for (int i = 0; i < 3; i++) {
        cnt = 0;
        for (int j = 0; j < 20; j++) {
            if (*(*(str+i)+j) == 'a') cnt++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

이 코드에서는 괄호가 좀 여러개 있어서if(*(*(str+i)+j) ~~ 괄호를 하나 없애보려고 또 다른 코드를 짜봤다

#include <stdio.h>
int main() {
    int cnt = 0;
    char* p, * q;
    char *str[3] = { "Time is gold","No pain no gain","No sweat no sweet" };

    for (p=str; p <str+ 3; p++) {
        cnt = 0;
        for (q=*p; q<*p+20 ; q++) {
            if (*q == 'a') cnt++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

근데 이건 실행이 잘 안 된다. 아무것도 안 뜬다.

이 이유를 알아내는데 한 달이 걸렸다.

#include <stdio.h>
int main() {
    int cnt = 0;
    char** p, * q;
    char* str[3] = { "Time is gold","No pain no gain","No sweat no sweet" };

    for (p = str; p < str + 3; p++) {
        cnt = 0;
        for (q = *p; q < *p + 20; q++) {
            if (*q == 'a') cnt++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

이렇게 써야 한다.

char** p, * q;

이중 배열이니까 이중 포인터로 써줘야 한다.

p가 str의 주소를 가리키고, q는 str의 주소를 가리키는 p를 또 가리켜야 하니까 p는 가장 깊숙히 있는 포인터이므로 **p를 써야 하고, q는 그 다음 바깥쪽에 있는 포인터이므로 *q로 쓰면 된다.

728x90

'언어 > C' 카테고리의 다른 글

연결리스트  (0) 2022.05.02
달팽이 배열  (0) 2022.03.30
재귀함수 시리Z  (0) 2022.03.23
함수 안에서 동적할당을 사용했을 때 free는 언제해야 하지?  (0) 2022.03.16
[백준] 1032번- 명령 프롬프트  (1) 2022.01.27