C언어) 포인터 - 포인터 기초

Lapis0875·2022년 10월 19일
1

c언어

목록 보기
1/21
post-thumbnail

📑포인터 시리즈

C언어에는 두개의 별이 있다고 종종 말하곤 해요. 하나는 별찍기 문제, 다른 하나는 포인터라고 해요. 처음 만나면 어렵고 이해하기 힘든 포인터, 시험공부 하는 김에 정리해볼게요.
포인터 이야기는 총 5편 가량의 분량으로 진행해보고자 해요. 어려운 내용이기도 하고, 포인터로 다룰 수 있는 개념이 많아 글을 나눴으니 모두 읽어주세요 😉

📱메모리

다른 언어들도 그렇지만, C언어는 변수 등을 메모리 위에 할당해요.

int a = 10;		// 변수 a를 위한 메모리 할당.
int b = 5, c;		// 변수 b, c를 위한 메모리 할당.

우리는 할당된 메모리 공간을 변수 이름을 통해 접근할 수 있어요.

printf("a = %d\n", a);		// 변수 a의 메모리 공간에 저장된 값을 읽음.

❓포인터란 무엇인가요

포인터란, 이름 그대로 특정 메모리 주소를 가리키는 (point) 자료형을 말해요. 어라? 분명 앞서 변수 등을 선언할 때 메모리 공간을 할당받는다고 이야기했었네요. 그렇다면 포인터로 다른 변수의 메모리 공간을 가리킬 수 있지 않을까요?

여기 100이라는 값을 가지고 있는 int형 변수 i가 있습니다.

int i = 100;

포인터가 다른 메모리의 공간을 가리킬 수 있다면, 변수 i의 메모리 공간을 가리키게 해볼거에요.

int *p;
p = &i;

어라? 처음 보는 구문이 벌써 2가지 나왔네요. 하나씩 정리해볼게요.

기존에 int i; 처럼 사용하는 것과 달리, 앞에 *을 사용했어요. 이렇게 *을 사용해 선언한 변수는 포인터 변수가 돼요.

int *p;

i는 아까 선언했던 int형 변수인데, 앞에 붙은 &은 무엇일까요? &은 주소 연산자로, 이 변수가 가리키는 메모리 공간의 주소를 알려줘요. 포인터 변수가 특정한 메모리 공간을 가리키려면, 어딜 가리킬지 주소를 알아야겠죠? 여기서는 변수 i의 메모리 공간을 가리키게끔 주소를 정해줬어요.

p = &i;

& 연산자가 주소를 알려준다면, 아래의 구문들은 어떻게 동작할까요?

p = &2;				// 상수 앞 주소 연산자.
p = &(i + 10)		// 수식 앞 주소 연산자.

주소 연산자는 오로지 변수의 주소값을 알려줘요. 그래서, 상수나 수식 앞에는 사용할 수 없어요.

💡포인터를 다뤄봐요

포인터가 특정 메모리 공간의 주소를 가리킨다면, 이 포인터를 활용해 무엇을 할 수 있을까요?

int i = 100, *p;			 // int형 변수 i와 int형의 포인터 변수 p를 선언.
p = &i;						 // p에 i의 주소를 할당.


printf("i의 값 : %d\n", *p);	// i의 값 출력하기

*p = 200;					 // i의 값 변경하기
printf("변경된 i 값 : %d\n", i);

앞서 본 주소 연산자 &과 유사하게, *을 포인터 변수 앞에 사용하고 있어요. 이를 역참조 연산자라고 불러요. 포인터 변수에 사용해, 이 포인터가 가리키는 메모리 공간에 접근할 수 있어요.

아래 코드를 보면, i의 값을 출력하는데 변수 i 대신 포인터 변수 p를 사용하고 있어요. 실행해 보면 i의 값인 100이 출력돼요.

printf("i의 값 : %d\n", *p);

아래 코드를 보면, 포인터 변수 p에 200이라는 새 값을 할당하고 있어요. 이후 i의 값을 출력해보면, 200으로 바뀌어 있는 사실을 확인할 수 있어요.

*p = 200;
printf("변경된 i 값 : %d\n", i);

역참조 연산자를 사용해, 메모리 공간에 저장된 값을 읽거나 값을 바꿀 수 있어요.

⚠️포인터, 이런 부분은 주의해주세요

포인터 변수에 주소를 할당 할 때, 보통은 특정 변수에 주소 연산자를 사용해 할당해요. 하지만 아래와 같은 경우는 어떨까요?

// 아래 예제에서 사용할 변수들이에요.
int i, *p;
register int v;

아래와 같이는 사용할 수 있어요. 포인터 변수에 0을 넣어주는 경우는, p = NULL 과 같아요.

// 이렇게는 써도 돼요!
p = 0;
p = &i;

아래와 같이 포인터 변수에 직접 정수 값을 할당하면 컴파일러가 경고해줘요. 정수 값을 int* 형으로 명시적으로 형변환 해준다면 경고가 뜨진 않지만, 이 포인터 변수에 역참조 연산자를 사용한다면, 세그먼트 오류가 발생해요.

// 이렇게는 쓰지 말아주세요.
p = 3000;
p = (int *) 1776;

printf("*p = %d\n", *p);

gcc에서 컴파일 한 후, 실행하는 모습이에요.

앞서 언급했던 것처럼, 주소 연산자는 오로지 변수에만 사용할 수 있어요. 수식에 주소 연산자를 사용할 경우 오류가 발생해요.
v는 앞서 register 변수로 선언되었어요. register 변수에는 주소 연산자를 사용할 수 없어서, 오류가 발생해요.

// 이렇게는 오류가 발생해요.
p = &(i + 99);
p = &v;

배운 내용들을 정리해보고 있어요. 잘못 기재된 내용이 있다면, 댓글로 지적해주시면 수정할게요!

profile
새내기 대학생 개발자에요 :D

1개의 댓글

comment-user-thumbnail
2023년 3월 31일

👍

답글 달기