Categories: C

C 언어에서 포인터를 활용한 문자열 조작 예제

C 언어의 꽃이라 불리는 포인터, 그 매력적인 세계를 탐험해 보실 준비가 되셨나요? 포인터는 C 언어의 강력한 기능 중 하나이지만, 많은 분들이 어려워하는 부분이기도 합니다. 특히 문자열 조작에서 포인터를 효율적으로 사용하는 것은 C 프로그래밍의 핵심 역량이라고 할 수 있습니다.

이 블로그 포스팅에서는 ‘C 언어에서 포인터를 활용한 문자열 조작 예제‘를 통해 포인터에 대한 이해를 높이고, 실제로 활용할 수 있는 방법을 알려드리겠습니다. ‘포인터 기초와 문자열 표현’부터 시작하여 ‘문자열 복사 함수 구현’, ‘문자열 길이 계산 함수 만들기’, 그리고 ‘포인터를 이용한 문자열 역순 출력’까지, 단계별로 친절하게 설명해 드릴 예정입니다.

포인터의 개념을 확실히 잡고, C 언어로 문자열을 자유자재로 다루는 방법을 익혀보세요!

 

 

포인터 기초와 문자열 표현

C 언어의 꽃이라 불리는 포인터! 마치 마법 지팡이처럼 메모리의 세계를 자유자재로 다룰 수 있게 해주는 강력한 도구죠. 특히 문자열 조작에 있어서 포인터는 그 진가를 발휘합니다. 그럼, 포인터의 기본 개념부터 차근차근 살펴보면서 문자열과 어떻게 연결되는지 알아볼까요?

포인터란 무엇인가?

먼저, 포인터가 무엇인지부터 명확히 짚고 넘어가야겠죠? 간단히 말해서, 포인터는 메모리의 특정 위치를 가리키는 변수입니다. 마치 집 주소처럼 말이죠! 변수가 값을 저장하는 상자라면, 포인터는 그 상자의 위치를 기억하는 메모장과 같다고 생각하시면 됩니다. 이때 포인터가 가리키는 위치에 저장된 값에 접근하려면 어떻게 해야 할까요? 바로 * 연산자(dereference operator)를 사용하면 됩니다. 마치 메모장에 적힌 주소로 찾아가서 상자를 열어보는 것과 같습니다.

C에서의 문자열 표현

자, 그럼 이제 C에서 문자열이 어떻게 표현되는지 살펴보겠습니다. C에서는 문자열을 문자들의 배열로 다룹니다. ‘C’ 라는 단일 문자는 작은따옴표(”)로 감싸지만, “C”처럼 큰따옴표(“”)로 감싼 문자열은 실제로 ‘C’, ‘\0’ 와 같이 문자 ‘C’와 널 종료 문자(null terminator) ‘\0’로 구성된 배열로 저장됩니다. 놀랍지 않나요?! 이 널 종료 문자는 문자열의 끝을 알리는 중요한 역할을 합니다. 마치 문장의 마침표와 같은 역할이죠. 만약 ‘\0’가 없다면 프로그램은 문자열의 끝을 알 수 없어서 엉뚱한 메모리 영역까지 읽어버리는 대참사가 발생할 수도 있습니다! (으악!)

포인터와 문자열의 관계

포인터와 문자열의 관계를 더 자세히 알아보기 위해 예시를 하나 들어보겠습니다. char *str = "Hello"; 라는 코드가 있다고 가정해 봅시다. 이 코드는 str이라는 포인터 변수를 선언하고, “Hello”라는 문자열의 시작 주소를 저장합니다. 즉, str 포인터는 ‘H’ 문자를 저장하고 있는 메모리 위치를 가리키게 되는 것이죠. *(str + 1)과 같이 포인터 연산을 사용하면 ‘e’에 접근할 수 있습니다. 신기하지 않나요? 포인터 연산을 통해 문자열의 각 문자에 접근할 수 있다니!

여기서 중요한 점은, 포인터 변수 str 자체는 “Hello”라는 문자열 전체를 저장하고 있는 것이 아니라, 단지 문자열의 시작 주소만을 저장하고 있다는 것입니다. 마치 지도에서 도시 이름은 표시되어 있지만, 도시 전체가 지도 안에 들어있는 것은 아닌 것과 같은 이치입니다. str 포인터를 통해 문자열의 각 문자에 순차적으로 접근할 수 있도록 설계되어 있는 것이죠.

문자열의 길이 계산

그렇다면 문자열의 길이는 어떻게 알 수 있을까요? 바로 널 종료 문자 ‘\0’ 덕분입니다! ‘\0’ 문자를 만날 때까지 문자를 하나씩 세어 나가면 문자열의 길이를 계산할 수 있습니다. 이 원리를 이용하여 문자열의 길이를 계산하는 함수를 직접 만들어 볼 수도 있겠죠? (두근두근!)

포인터를 사용한 문자열 처리의 효율성

포인터를 사용하면 문자열을 매우 효율적으로 다룰 수 있습니다. 예를 들어, 문자열을 복사할 때, 포인터를 사용하면 문자열의 내용 전체를 복사하는 대신 시작 주소만 복사하면 되므로 메모리 사용량과 처리 시간을 크게 줄일 수 있습니다. 효율적인 메모리 관리는 프로그램 성능 향상의 핵심이라는 사실, 잊지 마세요!

포인터 사용 시 주의사항

포인터는 마치 양날의 검과 같아서, 잘 사용하면 강력한 도구가 되지만, 잘못 사용하면 프로그램에 예상치 못한 오류를 발생시킬 수 있습니다. 포인터를 사용할 때는 항상 주의를 기울여야 합니다. 특히, 초기화되지 않은 포인터를 사용하거나, 메모리 범위를 벗어난 접근을 시도하는 것은 매우 위험합니다! (조심, 또 조심!)

자, 이제 포인터와 문자열의 기본적인 관계를 이해하셨나요? 다음에는 포인터를 활용하여 문자열을 복사하는 함수를 직접 구현해보면서 더욱 깊이 있는 내용을 살펴보도록 하겠습니다. 기대해주세요!

 

문자열 복사 함수 구현

C 언어에서 문자열은 단순히 char 타입의 배열로 표현되죠?! 널 종료 문자(\0)는 문자열의 끝을 알리는 아주 중요한 역할을 합니다. 이 널 종료 문자를 꼭 기억해 두세요!! 이 널 종료 문자(\0) 없이는 문자열의 끝을 알 수 없어 오류가 발생하기 쉽거든요~?

문자열 복사 함수 만들기

자, 그럼 이제 본격적으로 문자열을 복사하는 함수를 직접 만들어 볼까요? 표준 라이브러리 함수인 strcpy()는 이미 존재하지만, 이 함수의 내부 동작 원리를 이해하는 것은 포인터 활용 능력 향상에 아주 큰 도움이 된답니다! 게다가 가끔은 strcpy()보다 더욱 최적화된 함수가 필요할 수도 있으니, 직접 구현하는 방법을 아는 것은 정말 중요해요!

#include <stdio.h>

char* my_strcpy(char *dest, const char *src) {
    char *original_dest = dest; // dest의 초기값 저장: 나중에 dest를 반환하기 위해!

    // src의 문자를 dest에 하나씩 복사하고, 널 종료 문자를 만날 때까지 반복!
    while (*src != '\0') {
        *dest = *src;
        dest++; // 다음 문자 위치로 이동!
        src++;  // 다음 문자 위치로 이동!
    }

    *dest = '\0'; // dest 문자열의 끝에 널 종료 문자 추가! 필수!!

    return original_dest; // 복사된 문자열의 시작 주소 반환!
}

int main() {
    char source[] = "Hello, world!"; // 원본 문자열: 13자 + 널 종료 문자 = 14바이트!
    char destination[20]; // 복사될 문자열: 충분한 크기 확보는 필수! (최소 14바이트 필요)

    // 직접 만든 my_strcpy 함수를 사용하여 문자열 복사!
    my_strcpy(destination, source);

    printf("원본 문자열: %s\n", source);
    printf("복사된 문자열: %s\n", destination);

    // 문자열 길이가 같음을 확인!
    int source_len = 0;
    while (source[source_len] != '\0') {
        source_len++;
    }
    int dest_len = 0;
    while (destination[dest_len] != '\0') {
        dest_len++;
    }
    printf("원본 문자열 길이: %d\n", source_len);
    printf("복사된 문자열 길이: %d\n", dest_len);


    // 다른 예시: 빈 문자열 복사
    char empty_string[] = "";
    char destination2[10];
    my_strcpy(destination2, empty_string);
    printf("빈 문자열 복사 결과: %s (길이: %lu)\n", destination2, strlen(destination2));


    // 또 다른 예시: 긴 문자열을 짧은 배열에 복사할 경우 (주의!!)
    char long_string[] = "This is a very long string!";
    char short_destination[5]; // 버퍼 오버플로우 발생 가능성!! 매우 위험!!
    my_strcpy(short_destination, long_string); // 이 함수 호출은 위험합니다!
    printf("짧은 배열에 긴 문자열 복사 결과: %s\n", short_destination); // 예측할 수 없는 결과 초래!


    return 0;
}

const 키워드의 중요성

my_strcpy 함수에서 const char *src 처럼 const 키워드를 사용하는 이유는 뭘까요? 바로 src가 가리키는 원본 문자열은 변경되지 않도록 보호하기 위해서랍니다! 이 작은 키워드 하나가 프로그램의 안정성을 높여주는 중요한 역할을 하죠~!

포인터 활용의 핵심

destsrc 포인터를 이용해서 한 글자씩 복사하는 부분이 이 함수의 핵심입니다! *srcsrc가 가리키는 위치의 문자 값을 가져오고, *dest = *src는 그 값을 dest가 가리키는 위치에 저장하는 역할을 합니다. 마치 택배 기사님처럼 값을 안전하게 전달하는 거죠! 그리고 dest++, src++를 통해 다음 문자 위치로 포인터를 이동시키는 것도 잊지 말아야 해요! 이 부분이 없다면 같은 위치에 계속 값을 덮어쓰게 되어버리니까요~?!

널 종료 문자의 중요성

마지막으로, dest 문자열의 끝에 널 종료 문자(\0)를 추가하는 것은 정말정말 중요해요!! 이 널 종료 문자가 없으면 문자열의 끝을 알 수 없어서 예상치 못한 오류가 발생할 수 있습니다! 꼭 명심하세요!

자, 이제 여러분도 자신만의 strcpy 함수를 만들어 사용할 수 있겠죠? 포인터를 잘 활용하면 이처럼 문자열 처리를 더욱 효율적이고 유연하게 할 수 있답니다! 더 많은 연습을 통해 C 언어 포인터 마스터가 되어보세요! 화이팅!!

 

문자열 길이 계산 함수 만들기

C 언어에서 문자열은 null 문자(‘\0’)로 끝나는 char형 배열로 표현됩니다. 이 null 문자는 문자열의 끝을 나타내는 중요한 표지판과 같죠! 마치 보물지도에서 ‘X’가 보물의 위치를 알려주듯이 말이에요. 그렇다면, 이러한 문자열의 길이를 어떻게 계산할 수 있을까요? 🤔 바로 strlen() 함수를 직접 만들어보면서 그 원리를 파헤쳐 보겠습니다! 준비되셨나요?! 😄

문자열 길이 계산 함수의 기본 형태

자, 먼저 문자열 길이를 계산하는 함수의 기본적인 형태를 살펴봅시다. 함수는 문자열의 시작 주소를 받아서, 그 길이를 정수형으로 반환해야 합니다. 마치 자로 길이를 재듯이 말이죠. 📏 C 코드로 표현하면 다음과 같습니다.

int my_strlen(const char *str) {
  // ... (여기에 길이 계산 로직이 들어갑니다!)
}

const char *str 부분이 바로 문자열의 시작 주소를 받는 부분입니다. const 키워드는 함수 내부에서 문자열을 수정하지 않겠다는 약속과 같습니다. 🤝 int는 함수가 정수형 값, 즉 문자열의 길이를 반환한다는 것을 의미합니다.

함수 내부 로직

이제 함수 내부 로직을 채워 넣어 봅시다! 핵심 아이디어는 포인터를 이용하여 문자열의 시작부터 끝(null 문자)까지 이동하면서 문자의 개수를 세는 것입니다. 마치 한 걸음씩 걸어가면서 걸음 수를 세는 것과 같죠! 🚶‍♂️🚶‍♀️ 다음 코드를 확인해 보세요.

int my_strlen(const char *str) {
  int length = 0;
  while (*str != '\0') {  // null 문자를 만날 때까지 반복!
    length++;             // 문자 개수 증가!
    str++;               // 다음 문자로 이동! (포인터 연산의 마법 ✨)
  }
  return length;        // 계산된 길이 반환!
}

*str는 현재 포인터가 가리키는 위치의 문자 값을 의미합니다. str++는 포인터를 다음 문자 위치로 이동시키는 연산입니다. 이 두 가지 연산이 마치 찰떡궁합처럼 🤝 작용하여 문자열의 끝까지 탐색할 수 있도록 해줍니다! null 문자(‘\0’)를 만나면 반복문이 종료되고, 지금까지 센 문자의 개수가 바로 문자열의 길이가 됩니다. 참 쉽죠? 😊

이렇게 직접 my_strlen() 함수를 만들어 봄으로써, 문자열의 길이를 계산하는 원리를 더욱 깊이 이해할 수 있게 되었습니다! 🎉 하지만, 실제 프로그램에서는 이미 잘 만들어진 strlen() 함수가 표준 라이브러리에 제공되므로, 굳이 직접 만들 필요는 없습니다. 하지만, 이러한 연습을 통해 포인터와 문자열에 대한 이해도를 높일 수 있다는 점! 잊지 마세요! 😉

`my_strlen()` 함수 사용 예제

자, 그럼 이제 my_strlen() 함수를 실제로 사용해 보는 예제를 살펴보겠습니다.

#include <stdio.h>

int my_strlen(const char *str) {
  // ... (위에서 구현한 함수 코드)
}

int main() {
  char str1[] = "Hello, world!";
  char str2[] = "C programming is fun!";

  int len1 = my_strlen(str1);
  int len2 = my_strlen(str2);

  printf("str1의 길이: %d\n", len1); // 출력: str1의 길이: 13
  printf("str2의 길이: %d\n", len2); // 출력: str2의 길이: 21

  // 표준 strlen() 함수와 비교!
  printf("표준 strlen(str1): %lu\n", strlen(str1)); // 출력: 표준 strlen(str1): 13
  printf("표준 strlen(str2): %lu\n", strlen(str2)); // 출력: 표준 strlen(str2): 21

  return 0;
}

위 예제에서는 “Hello, world!”와 “C programming is fun!” 두 개의 문자열에 대해 my_strlen() 함수를 사용하여 길이를 계산하고 출력하는 모습을 보여줍니다. 그리고 표준 strlen() 함수의 결과와 비교하여, 우리가 만든 함수가 제대로 작동하는지 확인할 수 있도록 했습니다. 결과가 동일하게 나오는 것을 확인할 수 있죠? 💯 정말 멋지지 않나요?! 🤩

이처럼 포인터를 활용하면 문자열을 훨씬 효율적으로 다룰 수 있습니다. 마치 마법사가 마법 지팡이를 사용하듯이 말이죠! 🧙‍♂️ 앞으로도 C 언어의 세계를 탐험하면서 포인터의 강력한 힘을 경험해 보세요! 🚀

 

포인터를 이용한 문자열 역순 출력

드디어! C 언어에서 포인터를 활용한 문자열 조작의 꽃이라고 할 수 있는, 문자열 역순 출력에 대해 알아볼 시간입니다~ 이전에 배운 포인터 기초와 문자열 표현, 문자열 복사, 문자열 길이 계산 함수들을 잘 익히셨다면, 이번 내용은 더욱 흥미진진하게 느껴지실 거예요!

문자열 역순 출력 방법

자, 그럼 시작해 볼까요? 문자열을 역순으로 출력하는 방법은 여러 가지가 있지만, 포인터를 사용하면 메모리 접근을 직접 제어하여 효율적인 코드를 작성할 수 있다는 장점이 있습니다. 특히, 임베디드 시스템이나 메모리 관리가 중요한 환경에서는 이러한 포인터 활용 능력이 정말 중요해지죠!

포인터를 사용한 문자열 역순 출력

일반적으로 문자열 역순 출력 함수를 생각해 보면, 문자열의 시작과 끝 지점을 나타내는 두 개의 포인터를 사용하는 방법이 가장 먼저 떠오를 겁니다. 바로 그 방법을 사용할 겁니다. 시작 포인터는 문자열의 첫 번째 문자를 가리키고, 끝 포인터는 마지막 문자를 가리키도록 설정합니다. 그리고 이 두 포인터가 서로 교차할 때까지, 가리키는 문자를 서로 바꿔주면 됩니다.

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

void reverse_string(char *str) {
    char *start = str; // 시작 포인터 설정
    char *end = str + strlen(str) - 1; // 끝 포인터 설정 (널 문자는 제외)

    // 두 포인터가 교차할 때까지 반복
    while (start < end) {
        char temp = *start; // 시작 포인터가 가리키는 값을 임시 변수에 저장
        *start = *end; // 끝 포인터가 가리키는 값을 시작 포인터 위치에 저장
        *end = temp; // 임시 변수에 저장된 값을 끝 포인터 위치에 저장

        start++; // 시작 포인터를 다음 문자로 이동
        end--; // 끝 포인터를 이전 문자로 이동
    }
}

int main() {
    char str[] = "Hello, World!";
    printf("Original string: %s\n", str);

    reverse_string(str);
    printf("Reversed string: %s\n", str);

    return 0;
}

reverse_string 함수 설명

위 코드를 보면, reverse_string 함수는 문자열을 가리키는 포인터 str을 인자로 받습니다. start 포인터는 str과 동일한 위치를 가리키도록 초기화되고, end 포인터는 strlen 함수를 이용하여 문자열의 끝 부분(널 문자 바로 앞)을 가리키도록 초기화됩니다. strlen 함수는 문자열의 길이를 반환하는데, 널 문자는 길이에 포함되지 않으므로 1을 빼줘야 정확한 위치를 가리킬 수 있습니다.

while 루프는 start 포인터가 end 포인터보다 앞에 있는 동안 계속 실행됩니다. 루프 내부에서는 temp 변수를 사용하여 startend 포인터가 가리키는 문자를 교환하고, start 포인터는 증가, end 포인터는 감소시켜 다음 문자들을 가리키도록 합니다. 이 과정을 반복하면서 문자열의 순서가 뒤집히게 되는 것이죠!

main 함수 설명

main 함수에서는 “Hello, World!”라는 문자열을 예시로 사용하여 reverse_string 함수를 호출하고, 결과를 출력합니다. 실행 결과는 다음과 같습니다.

Original string: Hello, World!
Reversed string: !dlroW ,olleH

원하는 대로 문자열이 역순으로 출력되었습니다! 이처럼 포인터를 사용하면 문자열을 직접 조작하여 원하는 결과를 효율적으로 얻을 수 있습니다. 물론, 다른 방법들도 존재하지만, 포인터를 사용하는 방법은 메모리 효율성 측면에서 매우 유리하다는 것을 꼭 기억해 주세요! 그리고 이러한 포인터 활용 능력은 C 언어 프로그래밍에서 매우 중요한 부분이니, 꼭 익숙해지시길 바랍니다.

strlen 함수 설명

strlen 함수는 문자열의 길이를 계산하는 데 사용되는데, 문자열의 시작 주소부터 널 문자(‘\0’)가 나타날 때까지의 문자 개수를 반환합니다. 널 문자는 문자열의 끝을 나타내는 특수 문자이죠! 만약 널 문자가 없는 문자열을 strlen 함수에 전달하면, 정의되지 않은 동작이 발생할 수 있으니 주의해야 합니다. 따라서 문자열을 다룰 때는 항상 널 문자의 존재를 확인하는 습관을 들이는 것이 좋습니다!

start

start < end 조건을 사용하는 이유는 만약 start <= end 조건을 사용한다면, 문자열의 가운데 문자가 두 번 바뀌는 현상이 발생할 수 있기 때문입니다. 예를 들어, “abc”라는 문자열을 역순으로 출력할 때, start <= end 조건을 사용하면 ‘b’ 문자가 자기 자신과 두 번 교환되는 불필요한 연산이 발생하게 됩니다. 따라서 start < end 조건을 사용하여 불필요한 연산을 방지하고 효율성을 높이는 것이죠!

이처럼 작은 부분 하나하나까지 신경 쓰는 것이 좋은 코드를 작성하는 비결입니다! C 언어의 매력은 이러한 세세한 부분까지 제어할 수 있다는 점이죠! 포인터를 잘 활용하면 메모리 관리 측면에서도 효율적인 코드를 작성할 수 있으니, 꾸준히 연습하고 익혀서 C 언어 마스터가 되어보세요!

 

지금까지 C 언어에서 포인터를 활용하여 문자열을 다루는 다양한 방법을 살펴보았습니다. 포인터는 단순히 변수의 주소를 저장하는 것 이상으로, 문자열과 같은 데이터 구조를 효율적으로 조작하는 강력한 도구입니다. 직접 문자열 복사 함수와 길이 계산 함수를 구현하고, 역순 출력까지 해보면서 포인터의 활용법을 더욱 깊이 이해하셨을 것입니다. 이러한 경험을 바탕으로 여러분의 C 프로그래밍 실력 향상에 도움이 되셨기를 바랍니다. 더 나아가, 배운 내용을 응용하여 다양한 문자열 처리 함수를 직접 만들어보고, C 언어의 매력을 더욱 탐구해보시기를 권장합니다. 포인터C 언어의 핵심 개념 중 하나이니, 꾸준한 연습을 통해 완전히 숙달하여 활용도를 높여보세요.

Itlearner

Share
Published by
Itlearner

Recent Posts

R에서 기본 그래프 그리기 (plot(), barplot(), hist())

안녕하세요! 데이터 시각화, 어떻게 시작해야 할지 막막하셨죠? R을 이용하면 생각보다 훨씬 쉽고 재밌게 그래프를 그릴…

3시간 ago

R에서 날짜 및 시간 데이터 처리 (as.Date(), lubridate 패키지 활용)

안녕하세요! 데이터 분석하면서 골치 아픈 날짜, 시간 데이터 때문에 머리 싸매고 계신가요? 저도 그랬어요. 그래서…

7시간 ago

R에서 문자열 다루기 (paste(), substr(), stringr 패키지 활용)

안녕하세요! 데이터 분석하면서 은근히 까다로운 문자열 처리 때문에 골치 아팠던 적, 다들 있으시죠? 저도 그랬어요!…

12시간 ago

R에서 데이터 병합과 조인 (merge(), inner_join(), left_join())

안녕하세요, 여러분! 데이터 분석하면서 골치 아픈 순간들이 있죠? 그중 하나가 바로 여러 데이터들을 하나로 합쳐야…

18시간 ago

R에서 데이터 변환 (mutate(), transmute())

안녕하세요! 데이터 분석, 하고 싶지만 어려워서 망설이고 계셨나요? 괜찮아요! 제가 도와드릴게요. 오늘 우리가 함께 살펴볼…

22시간 ago

R에서 중복된 데이터 제거 (distinct(), duplicated())

데이터 분석 할 때, 똑같은 데이터가 여러 번 나오면 어떻게 해야 할까요? R을 사용한다면 걱정…

1일 ago