본문 바로가기
SW사관학교 정글/C언어와 친구들

[C언어와 친구들] C언어의 *포인트는 포인터

by 대범하게 2022. 10. 24.
반응형

1. 포인터

- 포인터란 특정한 데이터가 저장된 주소값을 보관하는 변수

- 즉, 포인터도 변수다!

- 메모리 상에 위치한 특정한 데이터의 (시작)주소값을 보관하는 변수

 

- 포인터 역시 변수이기에 다른 변수와 마찬가지로 형(type)을 가짐

- 즉, int형 데이터 주소값을 저장하는 포인터와 char형 데이터 주소값을 저장하는 포인터가 서로 다른다.

 

예를 들어, p라는 포인터가 int 데이터를 가리키고 싶다고 하면 다음과 같이 사용하면 된다.

// (포인터에 주소값이 저장되는 데이터의 형)* (포인터의 이름);
int* p;	// 라고 하거나

// (포인터에 주소값이 저장되는 데이터의 형) *(포인터의 이름);
int *p;	// 로 하면 된다.

이러면 위의 포인터 pint형 데이터의 주소값을 저장하는 변수가 된다. 

 

2. & 연산자

- 단항 & 연산자는 피연산자의 주소값을 불러오는 연산자

- 단항 & 연산자라고 하는 이유 ! => &는 AND 연산자와 기호가 같아서 AND 연산자에서는 & 기호를 두 개 연속으로 붙여 쓴다. A&&B와 같이 AND 연산자에서는 피연산자가 두 개 있어야 둘을 비교하는 반면, 포인터에서의 & 연산자는 피연산자 하나만을 필요로 한다. 

#include <stdio.h>
int main(){
    int a;
    a = 2;
    // 주소 연산자(&)를 붙여, 변수 a의 주소를 구함
    printf("%p \n", &a);
    // 출력 결과: 0x7fffffffd984
    return 0;
}

 

p = &a 로 포인터 p에 a의 주소값을 줬을 경우 결과값이 같은 것을 볼 수 있다. 

포인터 p에 들어있는 값: 0x7fffffffd96c
 int 변수 a가 저장된 주소: 0x7fffffffd96c

#include <stdio.h>
int main(){
    int *p;
    int a;

    p = &a;

    printf("포인터 p에 들어있는 값: %p\n", p);
    printf("int 변수 a가 저장된 주소: %p\n", &a);
    // 출력결과 
    // 포인터 p에 들어있는 값: 0x7fffffffd96c
    // int 변수 a가 저장된 주소: 0x7fffffffd96c
    return 0;
}

 

여기까지 요약 👻✨

1. 포인터는 특정 데이터의 주소값을 보관.

2. 포인터는 주소값을 보관하는 데이터의 형 or 포인터 이름에 *를 붙임으로써 정의

3. & 연산자로 특정한 데이터의 메모리 상의 주소값을 알아올 수 있다. 

 

3. * 연산자

* 연산자는 주소값에서 해당 주소값에 대응되는 데이터를 가져오는 연산자

- * 역시 곱셈 연산자로 사용하는 친구이지만, 피연산자가 2개일 때만 곱셈 연산자로 작동한다. 만약 피연산자가 하나만 있다면 *  연산자는 해당 포인터가 가리키는 데이터 값을 가져온다. 

#include <stdio.h>
int main(){
    int *p; // p는 정수형 변수를 가리키는 포인터
    int a; // a는 정수형 변수
    
    p = &a; // p는 이제 정수형 변수 a의 주소값을 가리킨다.
    a =2;
    printf("a의 값: %d\n", a);  
    printf("*p의 값: %d\n", *p); // 포인터 변수 앞에 *가 붙었으니 해당 주소값에 들어있는 데이터를 출력한다. 

    // 출력결과
    // a의 값: 2
    // *p의 값: 2
    return 0;

}

 

💡이해해. 외워. 

&a : a의 주소를 가져옴

*a : a를 주소로 하는 곳의 값

 

3. 상수 포인터

- C에서는 변수 앞에 const를 붙이면 그 변수와 변수에 대응하는 값은 상수로 처리된다.

- 즉, 어떤 짓을 해도 해당 변수의 값은 그 값을 상수로 선언한 순간부터 상수가 된다.

 

Q. 상수 const를 쓰는 이유는 무엇인가?

A. 절대 바뀌지 않은 것 같은 값에 const 설정을 해주면 혹여나 실수로 해당 값을 바꾸는 상황이 발생해도 에러가 뜨기 때문에 실수할 일이 없어진다. 

// 상수 포인터
#include <stdio.h>
int main(){
    int a;
    int b;
    const int* pa = &a;
    *pa = 3;    // 올바르지 않은 문장
    pa = &b;    // 올바른 문장
    return 0;
}
const int* pa = &a;

이 코드의 의미는 무엇인가?

const int형을 가리키는 포인터? => Nope

pa int형 포인터 변수인데, 이 포인터가 가리키는 값이 절대 바뀌면 안 된다는 것을 선언하는 것이다. 

 

따라서, const int*의 의미는 const int형 변수를 가리키는 것이 아니라 int형 변수를 가리키는데 그 값을 절대로 바꾸지 말라는 말이다. 헷갈리는 부분 .....

a 자체는 변수이니깐 자유롭게 값을 변경할 수 있다.

그런데 위에서는 상수 포인터 pa를 통해서 a를 간접적으로 가리키고 있다. 이는 컴퓨터에게 const인 변수를 가리키고 있다고 말해주는 것이기 때문에 *pa로 a의 값을 호출할 때는 a의 값을 바꿀 수 없다. 

 

즉, a=3; 이라고 선언하면 이는 오류가 아니다. a 자체를 다이렉트로 바꾸는건 a가 변수이기에 상관 없다. 

하지만 *pa=3; 의 경우 *pa로 a의 값을 호출할 때는 a의 값을 바꿀 수가 없다. 

 

또또.. 아래의 pa = &b는 옳은 문장이다. 

pa가 가리키는 주소에 해당하는 데이터를 바꿀 수 없는 것이지, pa 자체를 바꿀 수 없다고는 하지 않았다.

 

 

 

공부 참고 블로그)

포인터 설명 참고 

반응형