ABOUT ME

꾸준히 성장하는 토리 기록

  • C언어 개념 정리 (주소 연산자, 포인터 변수, 그리고 역참조 연산자)
    IT 자격증 공부/정보처리기사 2025. 3. 30. 16:08

    1. 주소 연산자(&)

    주소 연산자 &는 변수가 저장된 메모리의 위치(주소)를 알려줍니다.

    간단한 비유로 설명하자면,

    • 우리의 집이 변수라고 가정하면 ->  집 = 자세한 주소
    • 우리의 집의 주소(예: 서울시 강남구 ...)가 메모리 주소라고 이해할 수 있습니다.
    • 그런 의미에서 &는 "~의 주소는?"이라고 묻는 것과 같습니다.
    int number = 10;
    printf("%p", &number); // number 변수의 메모리 주소를 출력 (예: 0x7ffeeb0dbc4c)
    

     

    2. 포인터 변수(*)

    포인터 변수는  직접 데이터를 저장하지 않고, 다른 변수의 위치(주소)를 가리키는 역할을 합니다.

     

    💡 일반 변수와 포인터 변수의 차이점

    • 일반 변수: 데이터 값(예: 숫자, 문자)을 직접 저장
    • 포인터 변수: 다른 변수가 저장된 메모리 위치(주소)를 저장

    포인터 변수 선언 방법

    C 언어에서는 별표(*) 기호를 사용하여 포인터 변수를 선언합니다.

    int *ptr; // int형 포인터 변수 선언
    "ptr은 int형 변수의 주소를 저장할 수 있는 포인터 변수"라는 의미입니다.
     
    int number = 10;
    int *ptr; // int형 변수의 주소를 저장할 수 있는 포인터 변수 선언
    ptr = &number; // number의 주소를 ptr에 저장
    
    1. number는 값 10을 저장하는 일반 변수
    2. ptr은 number의 주소(0x1000)를 저장하는 포인터 변수
    3. ptr은 number를 "가리키고 있다"고 표현

     

    3. 역참조 연산자(*)

    역참조 연산자 *는 포인터가 가리키는 주소에 저장된 값을 가져옵니다.

    • 저장된 메모리 주소를 따라가서 "그 장소에 누가 살고 있지?"라고 묻는 것과 같습니다.
    int number = 10;
    int *ptr = &number; // number의 주소를 ptr에 저장
    printf("%d", *ptr); // 출력: 10 (ptr이 가리키는 주소에 있는 값)
    

     


    예시

    #include <stdio.h>
    
    int main() {
        int age = 25; // 일반 변수 선언 및 초기화
        
        // 주소 연산자 &: 변수의 메모리 주소를 알려줌
        printf("age 변수의 값: %d\n", age);        // 25
        printf("age 변수의 주소: %p\n", &age);     // 메모리 주소 (예: 0x7ffee40cbc4c)
        
        // 포인터 변수: 다른 변수의 주소를 저장
        int *agePtr;     // int형 포인터 변수 선언
        // 포인트 변수로 선언을 해야지만 다른 변수의 주소를 담을 수 있음
        agePtr = &age;   // age의 주소를 agePtr에 저장
        
        printf("agePtr에 저장된 주소: %p\n", agePtr);  // age와 동일한 주소
        
        // 역참조 연산자 *: 포인터가 가리키는 주소의 값을 가져옴
        printf("agePtr이 가리키는 값: %d\n", *agePtr); // 25
        
        // 역참조로 값 변경하기
        *agePtr = 30;    // agePtr이 가리키는 주소의 값(즉, age)을 30으로 변경
        printf("변경 후 age의 값: %d\n", age);     // 30
        
        return 0;
    }

     

    문자와 문자열에서의 활용

    문자열에서도 같은 개념이 적용됩니다.

    #include <stdio.h>
    
    int main() {
        char name[] = "John"; // 문자 배열(문자열)
        
        // 배열 이름 자체가 첫 번째 요소의 주소
        printf("name의 주소: %p\n", name);
        printf("name[0]의 주소: %p\n", &name[0]); // 위와 동일
        
        // 포인터로 문자열 다루기
        char *namePtr = name;  // name(즉, &name[0])의 주소를 namePtr에 저장
        
        // 역참조로 첫 번째 문자 출력
        printf("첫 번째 문자: %c\n", *namePtr);    // J
        
        // 포인터 산술 연산: 다음 문자의 주소로 이동
        printf("두 번째 문자: %c\n", *(namePtr+1)); // o
        
        return 0;
    }
    

     

     

    코드를 한 줄씩 설명하면 아래와 같습니다. 

    char name[] = "John"; // 문자 배열(문자열)
    

    이 줄은 "John"이라는 문자열을 저장하는 name이라는 문자 배열을 만듭니다. 메모리에는 다음과 같이 저장됩니다

    • name[0]: 'J'
    • name[1]: 'o'
    • name[2]: 'h'
    • name[3]: 'n'
    • name[4]: '\0' (문자열 끝을 나타내는 널 문자)
    printf("name의 주소: %p\n", name);
    

    여기서 name은 배열의 이름입니다. C 언어에서 배열 이름은 그 배열의 시작 주소를 나타냅니다.

    따라서 이 줄은 name 배열의 첫 번째 요소('J')가 저장된 메모리 주소를 출력합니다.

    printf("name[0]의 주소: %p\n", &name[0]); // 위와 동일
    

    &name[0]는 배열의 첫 번째 요소('J')의 주소를 명시적으로 가져옵니다. 이것은 위의 name과 정확히 같은 주소입니다.
    💡 &은 ~의 주소 와 같은 말이라는 점 꼭 기억하기! 

    char *namePtr = name;  // name(즉, &name[0])의 주소를 namePtr에 저장
    

    여기서는 포인터 변수(*) namePtr을 선언하고, (namePrt을 포인터 변수로 사용하겠다!!)
    근데, 그 변수에 name 즉, &name[0]의 주소를 namePtr에 저장하겠다. 라는 뜻입니다. 
    name 배열의 시작 주소를 이 포인터에 저장합니다. 이제 namePtr은 'J'가 저장된 메모리 위치를 가리킵니다.

    printf("첫 번째 문자: %c\n", *namePtr);    // J
    

    *namePtr는 namePtr이 가리키는 메모리 위치에 저장된 을 가져옵니다. 즉, 첫 번째 문자 'J'를 읽어옵니다.

    printf("두 번째 문자: %c\n", *(namePtr+1)); // o
    

    namePtr+1은 namePtr의 주소에 1을 더합니다. 이는 다음 문자('o')의 주소를 계산합니다. *(namePtr+1)은 그 주소에 저장된 값, 즉 'o'를 가져옵니다.

     

    메모리를 시각화해서 보면 아래처럼 이해할 수 있습니다.

    메모리 주소:  0x1000    0x1001    0x1002    0x1003    0x1004
               +--------+--------+--------+--------+--------+
    name 배열:  |   'J'   |   'o'   |   'h'   |   'n'   |  '\0'  |
               +--------+--------+--------+--------+--------+
    
    • name과 &name[0]는 모두 주소 0x1000을 가리킵니다.
    • namePtr도 0x1000을 저장합니다.
    • *namePtr는 0x1000 위치의 값인 'J'를 가져옵니다.
    • namePtr+1은 0x1001을 가리킵니다.
    • *(namePtr+1)은 0x1001 위치의 값인 'o'를 가져옵니다.

     

    댓글

SSOONTORY Blog.