본문 바로가기
프로그래밍/C언어

8-1. c언어 포인터와 상수

by 수삼이는코딩중 2023. 1. 31.
728x90

포인터

int a=10;

컴파일러는 컴퓨터에게 메모리 0x123456(임의의 16진수) 위치에서부터 4바이트의 공간에 있는 데이터를 10으로 바꾸어라!고 명령한다. (2진수 ...00001010) 로 저장될 것이다.

포인터는 특정한 데이터를 보관하는 '변수'이다. 바로, 특정한 데이터가 저장된 (시작)주소값을 보관하는 변수이다. 변수를 정의할 때 int 나 char처럼 여러가지 '형'(자료형)이 있는 것 처럼 포인터도 '형'이 있다.

포인터 기본구조

포인터에 주소값이 저장되는 데이터의 형 * 포인터의 이름
int*p;

이렇게 정의 하면 포인터 p는 int형 데이터의 주소값을 저장하는 변수가 되는 것이다.
그러면 이 변수에 값을 어떻게 집어넣지?
& 연산자를 사용하면 된다.
(a&b는 두개의 피연산자가 필요한 and 연산이고 포인터에서 사용되는 &은 피연산자가 하나인 단항 연산자이다)

기본구조

&주소값을 계산할 데이터

변수a의 주소값을 알고 싶다면 다음과 같이 쓰면 된다.

&a


실습

#include <stdio.h>
int main() {
	int a = 2;
	printf("%p \n", &a);
	return 0;
}

결과는 다음과 같다.

0000007EBB2FF6A4


포인터에 값을 집어넣어 보자.

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

	printf("포인터 : %p , a의 주소 : %p", p, &a);

	return 0;
}
포인터 : 0000008F3A0FF614 , a의 주소 : 0000008F3A0FF614


포인터에 저장된 주소값에 위치한 데이터 값 불러오기
기본구조

*포인터
*p

위의 식에 이어서 불러오면 결과는 다음과 같다.

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

	printf("a= %d , *p = %d", a, *p);
	return 0;
}
a= 2 , *p = 2


포인터가 가리키는 주소값에 데이터 저장도 가능하다.

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

	p = &a;
	*p = 2;

	printf("a= %d , *p = %d", a, *p);
	return 0;
}
a= 2 , *p = 2

p는 변수a의 주소값을 가리키고 있고, *p는 변수a의 주소값에 들어갈 데이터를 말하기 때문에 가능하다!

기억할것

int *p : 정수형의 데이터가 들어있는 주소값을 가질 p라는 포인터 선언
(왜 이렇게 포인터의 타입을 정할까? *p를 통해 데이터값을 불러들일 때, 정수형 변수를 가리키는 주소값임을 인식하여 4바이트를 읽어 들여 값을 바꿀 수 있게 된다)
p : 포인터 (주소값)
*p : 포인터의 위치에 있는 데이터값
p=&a : 포인터에 변수 a의 주소값 저장하기

포인터 p에 어떤 변수 a의 주소값이 저장되어 있다면 포인터 p는 변수 a를 가리킨다. (포인터도 엄연한 변수이기 때문에 특정한 메모리 공간을 차지한다.)

상수와 포인터

먼저 기억할 것은, 변수가 선언되면 변수에 저장되는 데이터의 메모리 주소가 정해진다. 따라서 변수에 저장되는 데이터가 바뀌어도 변수의 주소는 변하지 않는다. 따라서 포인터값도 변하지 않는다.

#include <stdio.h>
int main() {
	int a=3, b=4;
	int* p = &a;
	printf("%d\n", p);
	a = 5;
	printf("%d", p);
	return 0;
}
-686359708
-686359708

또한 포인터로 할 수 있는 것은 다음과 같다.

	*p = 4
	p = nullptr;

1. 포인터가 가리키고 있는 변수의 데이터 값을 바꿀 수 있다.
2. 포인터가 가리키는 대상을 바꿀 수 있다.

따라서 포인터변수와 const(상수)가 묶였을 때는 두가지 경우가 생긴다.
1. 포인터 변수가 가리키고 있는 변수의 데이터를 바꿀 수 없다. (포인터 변수가 가리키는 변수가 상수가 된다.)
2. 포인터 변수가 가리키고 있는 대상을 바꿀 수 없다. (포인트 변수 자신이 상수가 된다.)

상수와 포인터의 결합
(1) 포인터 변수가 가리키고 있는 변수의 데이터를 상수화 한것. (포인터변수 자체가 상수화 된것이 아니다.)

int a;
const int* p=&a;

(2) 포인터 변수 자체를 상수화 한것.

int a;
int* const p =a;


예를들어.
(1) 번은 포인터 변수가 가리키는 변수는 바뀔 수 있다.

#include <stdio.h>
int main() {
	int a=3, b=4;
	const int* p;
	
	p = &a;
	printf("%d", p);

	p = &b;
	printf("%d", p);
	

	return 0;
}

결과는 다음과 같다.

493877204
493877236

그러나 다음과 같이 상수화시킨 변수a의 값을 바꿀 수는 없다.

#include <stdio.h>
int main() {
	int a, b;
	const int* p = &a;

	*p = 3;

	return 0;
}


(2)번은 포인터 변수 자체가 상수화 되어서, 가리키는 변수a의 데이터는 바꿀 수 있다.

#include <stdio.h>
int main() {
	int a=3, b=4;
	int* const p = &a;

	*p = 5;
	printf("%d", a);

	return 0;
}
5

그러나 포인터 변수가 가리키는 변수 자체는 바꿀 수 없다. 다음 식은 성립이 안된다.

#include <stdio.h>
int main() {
	int a=3, b=4;
	int* const p = &a;

	p = &b;
	
	return 0;
}

(const 다음에 바로 p가 붙었으니까 p값이 바뀔 수 없다고 생각하면 편하다.)

const int* const p;

위의 식은 아무것도 못바꾼다. 즉, 포인터 변수 자체도, 포인터 변수가 가리키고 있는 변수의 데이터도 못바꾼다.

그리고 한가지 중요한 것.
(1)번은 포인터를 통해 "a라는 변수를 바꿀 수 있냐 없냐" 에 상수화 라는 limit을 걸어준거지 a 자체가 상수가 된 것은 아니다. 따라서 다른 포인터변수가 a를 가리키면 a값은 바꿀 수 있다. 즉, 포인터변수 자체가 변수에 대해 어찌 저찌하는 것에 limit을 걸어주는 것이다.

#include <stdio.h>
int main() {
	int a=3, b=4;
	const int* p = &a;

	// *p = 10; 안됨
	int* k = &a;
	*k = 100;
	printf("%d", a);
	
	return 0;
}
100

댓글