C 3주차 - 문자열

Gunter·2024년 3월 17일
0

C

목록 보기
10/13

문자열의 개념과 용도

문자열(string)은 간단히 말하면 문자의 집합을 뜻한다.
C언어는 문자 배열이나 포인터를 사용하여 문자열을 다룹니다.
문자열의 마지막에는 NULL 문자('\0')가 포함되어, 문자열의 끝을 나타낸다.
NULL 문자는 문자열의 길이를 결정하는 데 중요한 역할을 한다.

char data1 = 'H';
char data2 = 'e';
char data3 = 'l';
char data4 = 'l';
char data5 = 'o';

 







문자열의 선언과 초기화

 

문자 배열을 사용한 선언과 초기화

문자 배열을 사용하여 문자열을 선언하고 초기화하는 것은 문자열을 저장할 공간을 메모리에 직접 할당하는 방식이다.

char str1[14] = "Hello, World!"; // 명시적 크기 선언과 초기화
char str2[] = "Hello, World!";   // 컴파일러가 크기를 계산하여 할당

위의 예시에서 str1은 크기를 명시적으로 14로 지정했고(문자열 길이 + 널 문자), str2는 컴파일러가 문자열 리터럴의 길이를 계산하여 자동으로 크기를 할당한다. 두 경우 모두 배열의 끝에는 자동으로 널 문자('\0')가 추가되어 문자열의 끝을 나타낸다.

문자 포인터를 사용한 선언과 초기화

문자 포인터를 사용하여 문자열을 선언하고 초기화하는 방식은 문자열 리터럴의 주소를 포인터 변수에 저장하는 것이다. 이 방법으로 초기화된 문자열은 읽기 전용 메모리 영역에 저장된다.

char *str = "Hello, World!";

이 경우, str은 문자열 "Hello, World!"의 첫 번째 문자 'H'를 가리키는 포인터다. 문자열 리터럴은 프로그램의 읽기 전용 메모리 세그먼트에 저장되며, c을 통해 이 문자열에 접근할 수 있다.

 







문자열과 배열의 관계

C언어에서 문자를 저장하는 데 가장 적합한 자료형은 char형이다.
그래서 문자령릉 저장하려면 char형 변수를 그룹으로 묶어서 관리하는 char배열을 사용해야 한다.

  • 저장 방식 : 문자열은 내부적으로 문자 배열로 저장되며, 배열의 각 요소는 문자열을 구성하는 각 문자에 해당한다. 예를 들어, 문자열 "Hello"는 사실상 {'H', 'e', 'l', 'l', 'o', '\0'}라는 문자 배열로 메모리에 저장된다.
  • 접근 방식 : 문자열 내의 특정 문자에 접근하거나 수정할 때, 배열 인덱싱을 사용할 수 있디. 예를 들어, str[0]은 문자열 str의 첫 번째 문자를 가리킨다.
char data[6] = {'h', 'a', 'p', 'p', 'y', 0};
/* 문자 개수는 5개고 끝에 0을 덧붙여야 하므로 배열의 크기는 6 */

 







문자열과 포인터의 관계

다음과 같은 문자열 선언이 있을 때:

char str[] = "Hello";

str은 문자 배열을 가리키는 포인터다. 이 경우, str은 'H’를 가리키며, 이는 문자열의 첫 번째 문자이다.

문자열을 가리키는 포인터를 사용하면 문자열의 각 문자에 접근하거나 문자열을 수정하는 등의 작업을 수행할 수 있다. 예를 들어, 다음과 같이 문자열의 특정 문자에 접근할 수 있습니다:

char c = str[1];  /* 'e' */

또한, 문자열을 가리키는 포인터를 사용하면 문자열을 함수에 전달하거나 함수에서 반환하는 등의 작업을 수행할 수 있다.

 







문자열 관련 함수들

C언어에서 문자열을 다루기 위해 표준 라이브러리에서 제공하는 여러 함수들이 있다.
이 함수들은 <string.h> 헤더 파일에 선언되어 있으며, 문자열 복사, 비교, 연결, 검색 등 다양한 작업을 수행할 수 있게 해준다.

  1. String Copy: strncpy()
    -> 문자열 복사

  2. String Concate: strncat()
    -> 문자열 연결

/* 두 개의 문자열 합치기 */
#include <stdio.h>
#include <string.h>

void main(){
	char data[10] = {'a, 'b', 'c', 0,};
    char result[16];
    
    strcpy(result, data);
    strcat(result, "def");
    
    printf("%s + \"def\" = %s\n", data, result);
}
  1. String Compare: strncmp()
    -> 문자열 비교

  2. First Character Occurrence: strchr()
    -> 문자열 첫 발생 위치 찾기

  3. Last Character Occurrence: strrchr()
    -> 문자열 마지막 발생 위치 찾기

  4. String Search: strstr()
    -> 부분 문자열 첫 검색

  5. String Token Break: strtok()
    -> 구분기호 기준으로 문자열 토근 나누기

  6. Lowercase String: strlwr()
    -> 소문자 변환

  7. Uppercase String: strupr()
    -> 대문자 변환

  8. Duplicate String: strdup()
    -> 문자열 복제

  9. strlen(str): 문자열 str의 길이를 반환

#include <stdio.h>
#include <string.h>

void main(){
	int data_length; /* 문자열 길이를 저장할 변수 */
    char data[10] = {'h', 'a', 'p', 'p', 'y', 0};
    
    data_length = strlen(data);
    
    printf("data length = %d\n", data_length);
}

문자열 복사

  • strcpy(char *dest, const char *src): src 문자열을 dest로 복사합니다. dest가 충분히 크지 않아 오버플로우가 발생할 수 있으니 주의해야 합니다.
  • strncpy(char *dest, const char *src, size_t n): src 문자열의 처음 n개 문자를 dest로 복사합니다. 오버플로우를 방지할 수 있지만, n개 문자를 복사한 후 추가적으로 널 문자를 붙여주지 않는다는 점을 주의해야 합니다.

문자열 비교

  • strcmp(const char *str1, const char *str2): str1str2 문자열을 비교합니다. 두 문자열이 같으면 0을, str1str2보다 크면 양수를, 작으면 음수를 반환합니다.
  • strncmp(const char *str1, const char *str2, size_t n): str1str2 문자열의 처음 n개 문자를 비교합니다. 비교 방식은 strcmp와 동일합니다.

문자열 연결

  • strcat(char *dest, const char *src): src 문자열을 dest 문자열의 끝에 연결합니다. dest의 크기가 충분히 큰지 확인해야 합니다.
  • strncat(char *dest, const char *src, size_t n): src 문자열의 처음 n개 문자를 dest 문자열의 끝에 연결합니다. dest의 크기가 충분히 큰지 확인해야 하며, 연결 후 널 문자로 끝나는지 확인해야 합니다.

문자열 길이

  • strlen(const char *str): str 문자열의 길이를 반환합니다. 여기서 길이란 널 문자를 제외한 문자의 개수입니다.

문자열 검색

  • strchr(const char *str, int c): str 문자열에서 처음으로 c가 나타나는 위치의 포인터를 반환합니다. 만약 c가 문자열에 없으면 NULL을 반환합니다.
  • strrchr(const char *str, int c): str 문자열에서 마지막으로 c가 나타나는 위치의 포인터를 반환합니다.
  • strstr(const char *haystack, const char *needle): haystack 문자열 내에서 needle 문자열이 시작하는 첫 번째 위치의 포인터를 반환합니다. 만약 needlehaystack에 없으면 NULL을 반환합니다.

기타 함수

  • strtok(char *str, const char *delim): 문자열을 delim에 포함된 하나 이상의 문자를 기준으로 토큰으로 분리합니다. 첫 번째 호출에서는 문자열의 포인터를, 이후 호출에서는 NULLstr 인자로 제공해야 합니다.

 

















연습해보기

// 다음과 같은 코드를 이해해봅시다.
#include <stdio.h>

void reverse(char* str) {
    int len = 0;
    while(str[len] != '\0') {
        len++;
    }

    for(int i=0; i<len/2; i++) {
        char temp = str[i];
        str[i] = str[len-i-1];
        str[len-i-1] = temp;
    }
}

int main() {
    char str[] = "Hello, World!";
    reverse(str);
    printf("%s\\n", str);
    return 0;
}

!dlroW ,olleH\n










// 아래의 코드의 실행 결과를 예상하여 봅시다
#include <stdio.h>
#include <string.h>

int find_char(char* str, char c) {
    for(int i=0; str[i] != '\0'; i++) {
        if(str[i] == c) {
            return i;
        }
    }
    return -1;
}

int main() {
    char str[] = "Hello, World!";
    char c = 'o';
    int pos = find_char(str, c);
    if(pos != -1) {
        printf("The character '%c' found at position %d\\n", c, pos);
    } else {
        printf("The character '%c' not found\\n", c);
    }
    return 0;
}

The character 'o' found at position 4\n










  • strcat(), strcpy(), strcmp() 등등 기본 문자열 함수를 구현해보기 (string 헤더 include 금지!!)

myStrcat()

  1. 두 단어를 입력받는다.
  2. 두 단어를 합친 결과를 출력한다.
    ex)
    Input first word : Knock
    Input second word : On!
    KnockOn!
#include <stdio.h>


void myStrcat(char *dest, const char *src) {
    /* dest의 끝을 찾기 */
    while (*dest) {
        dest++;
    }
    /* src의 내용을 dest의 끝부터 복사 */
    while (*src) {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';
}

int main() {
    char firstWord[100];  
    char secondWord[100]; 

  
    printf("Input first word: ");
    scanf("%s", firstWord);
    printf("Input second word: ");
    scanf("%s", secondWord);

    
    myStrcat(firstWord, secondWord);

  
    printf("%s\n", firstWord);
    return 0;
}

 








myStrcpy()

  1. 단어를 입력받는다.
  2. 다른 배열에 문자열을 복사한 후 복사본을 출력한다.
    ex)
    Input word : KnockOn!
    KnockOn!
#include <stdio.h>


void myStrcpy(char *dest, const char *src) {
    /* src에서 dest로 문자를 하나씩 복사 */
    while (*src) {
        *dest = *src;
        dest++;
        src++;
    }

    *dest = '\0';
}

int main() {
    char originalWord[100]; 
    char copiedWord[100];  

    printf("Input word: ");
    scanf("%s", originalWord);


    myStrcpy(copiedWord, originalWord);


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

    return 0;
}

 








myStrcmp()

  1. 두 단어를 입력받는다.
  2. 두 단어의 비교 결과를 출력한다.
    ex)
    Input first word : Knock
    Input second word : On!
    Nope..
#include <stdio.h>


int myStrcmp(const char *str1, const char *str2) {
    /* str1과 str2를 한 글자씩 비교 */
    while (*str1 && (*str1 == *str2)) {
        str1++;
        str2++;
    }
    /* 두 문자열의 차이를 반환 */
    return *(const unsigned char*)str1 - *(const unsigned char*)str2;
}

int main() {
    char firstWord[100]; 
    char secondWord[100]; 


    printf("Input first word: ");
    scanf("%s", firstWord);
    printf("Input second word: ");
    scanf("%s", secondWord);

   
    int result = myStrcmp(firstWord, secondWord);


    if (result == 0) {
        printf("Same!\n");
    } else {
        printf("Nope..\n");
    }

    return 0;
}

 








  • 추가적인 문자열 함수 만들어 보기

void myNoSpace(char* str) {}

  1. 문장을 입력받는다.
  2. 문자열 사이 공백을 제거한 후 출력한다.
    ex)
    Input sentence : Hello Knock On!
    HelloKnockOn!
#include <stdio.h>


void myNoSpace(char* str) {
    char* dest = str; /* dest는 공백이 제거될 위치를 가리킴 */
    while (*str != '\0') {
        if (*str != ' ') { /* 현재 문자가 공백이 아니면, dest 위치에 복사하고 dest를 한 칸 이동 */
            *dest = *str;
            dest++;
        }
        str++; /* 원본 문자열에서 다음 문자로 이동 */
    }
    *dest = '\0'; /* 새로운 문자열의 끝에 널 문자를 추가 */
}

int main() {
    char sentence[100]; 

    
    printf("Input sentence: ");
    fgets(sentence, sizeof(sentence), stdin); /* fgets를 사용하여 공백을 포함한 문장을 입력 받음 */

 
    myNoSpace(sentence);


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

    return 0;
}

0개의 댓글