일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 프로그래머스
- alexnet
- 연결 리스트
- 코딩테스트
- 프로세스
- RxJS
- 웹팩
- 브라우저
- 자바스크립트
- 알고리즘
- GraphQL
- 컨테이너
- 큐
- vue3
- 프론트엔드
- C
- 포인터
- 해시테이블
- 타입스크립트
- 연결리스트
- 릿코드
- 자료구조
- 스택
- Machine Learning
- 이진탐색
- cors
- APOLLO
- 배열
- pytorch
- RT scheduling
- Today
- Total
프린세스 다이어리
[C] 포인터 개념, 활용방법 정리 본문
1. 포인터의 개념
이전까지 공부한 변수는 그 자체로 자신의 자료형에 맞는 값을 저장한다. int, double, char 등이 그 예시다. 포인터는 메모리의 주소 값 자체를 저장한다. int형 변수를 만들었다고 하면, 컴퓨터 어딘가에 int가 저장된 공간이 있을 것이고, 그것의 메모리 주소를 가리키고 있는 포인터도 있다. 포인터는 메모리 주소의 값을 가지기 때문에 컴퓨터 메모리에 바로 접근할 수 있다.
int a = 5;
int 5 값을 가지는 a 변수가 있고 이것의 메모리 주소는 0xAFB03912 라고 가정해 보자.
int *b = &a;
포인터는 int *b = &a; 처럼 선언할 때 * 연산자를 사용하여 포인터 변수임을 표현한다. 이 의미는 포인터 변수 b가 a의 메모리 주소를 가리키고 있다는 의미고, b의 값은 0xAFB03912이다. 포인터 b 또한 하나의 변수기 때문에, 메모리 주소를 또 다른 0xCA23AF29로 가진다. 선언 이후에 *b라고 쓰게 되면, 여기서는 *가 간접 참조 연산자로 포인터 변수 b가 가리키는 주소의 값, 즉 여기서는 a의 값인 5가 된다.
정리하면,
주소 연산자 (&) - 변수 앞에 붙어서 변수의 메모리 '시작' 주소값을 구한다.
포인터 (*) - 포인터 변수를 선언할 때 사용한다.
간접 참조 연산자 (*) - 선언된 포인터 변수가 가리키는 변수의 값을 구한다.
이때까지 별 생각 없이 scanf(); 를 사용할 때, &a 이렇게 써서 특정한 변수가 메모리 내에 존재하는 주소의 값을 가져오고 있던 것이었다.
#include <stdio.h>
int main(void) {
int a = 5;
int *b = &a;
printf("%d\n", *b);
}
출력 결과는 5다. 포인터 변수 b가 가리키고 있는 주소 값을 잘 출력하고 있다.
2. 포인터 활용해보기
배열의 원소의 주소값 출력하기
#include <stdio.h>
int main(void) {
int a[] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < 10; i++)
{
printf("%d\n", &a[i]);
}
}
결과는 다음과 같이 출력된다.
-421800320
-421800316
-421800312
-421800308
-421800304
-421800300
-421800296
-421800292
-421800288
-421800284
4씩 증가하면서 출력된다.
344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 |
... | ... | ... | 값 | 값 | 값 | 값 | ... | ... | ... |
실제로 int a = 5; 와 같이 변수를 할당하면, 메모리 주소 상에서는 위와 같이 기록된다. int형은 4 bytes를 차지하므로, 4칸을 차지한다. 배열을 이용하면 연속적인 공간에 값을 배치시킬 수 있기 때문에 위의 코드에서 배열의 메모리 주소가 4씩 증가하는 것이다.
포인터는 특정한 메모리 주소를 가리키는 변수이기 때문에, 이 변수의 메모리 주소를 가리키는 또다른 포인터를 만들 수도 있다.
#include <stdio.h>
int main(void) {
int a = 5;
int *b = &a;
int **c = &b;
printf("%d\n", **c);
}
이렇게 다중 포인터 또한 사용할 수 있다. 간혹 게임 등을 개발할 때 난독화 기법으로도 사용된다고 한다.
포인터는 컴퓨터 시스템의 특정한 메모리에 바로 접근할 수 있기 때문에, 기존에 존재하던 중요한 메모리 영역에 실수로 접근하지 않도록 해야 한다.
int *a = 0x3344af09;
*a = 0;
위와 같은 코드처럼, 특정한 포인터 변수에 어떠한 메모리 주소를 넣고 0으로 재할당해버리면, 우리는 해당 주소가 어떤 역할을 하고 있는지 모르기 때문에 우리가 컨트롤할 수 없게 될 수가 있다.
3. 배열과 포인터
배열과 포인터는 사실 동일하다. 배열을 선언한 이후에는, 배열의 이름 자체가 포인터 변수와 동일하다.
#include <stdio.h>
int main(void) {
int a[] = {1,2,3,4,5,6,7,8,9,10};
int *b = a;
printf("%d\n", b[2]);
}
변수 a에 배열을 할당하고 포인터 변수 b를 만들어서 &a가 아닌 a를 보게 만들면 3이 출력된다. 앞서 배열을 공부한 글에서 문자 배열을 입력받을 때 왜 scanf()에 &a가 아닌 a를 써야 하는지 이해되지 않았는데, 이 때문이었다.
'C, C++' 카테고리의 다른 글
[C] C언어에서 문자열을 다루는 방법, 문자열 관련 함수 정리 (0) | 2021.09.28 |
---|---|
[C] C언어에서 문자를 처리하는 방법, 문자와 버퍼의 관계 (0) | 2021.09.27 |
[C] 배열 선언방법, 문자열 정리 (0) | 2021.09.25 |
[C] 함수 문법 정리 (0) | 2021.09.25 |
[C] 반복문 문법 정리 (0) | 2021.09.24 |