-
포인터(Pointer)와 동적 메모리 할당Data Structure 2024. 4. 27. 01:55728x90
포인터는 C언어에서 메모리 관리와 데이터 구조를 효율적으로 다루고 제어하기 위한 핵심적인 도구이다.
그러나, C언어를 배우다가 포인터 부분이 나오면 힘들어 하는 사람들이 많다.
포인터가 복잡하고, 이해하기 까다로운 부분이 있는 것은 사실이지만, 단순히 포인터가 "이러이러한 개념이다"만 이해한다기 보다, C언어가 하드웨어와 밀접하게 상호 작용할 수 있는 언어임을 고려하여 포인터가 필요한 이유를 생각한다면 납득이 될 수 있을 것이다.
또한, 포인터와 동적 메모리 할당은 C언어 카테고리와 운영체제에서도 등장할 정도로 반드시 알아두어야 할 핵심 개념이다.
포인터란?
▶ 다른 변수의 주소를 가지고 있는 변수여기서, '주소'라는 것은 도대체 어떤 주소를 의미하는 것일까?
우리가 C언어에서 변수나 데이터를 선언하게 되면, 그 변수는 고유의 주소값을 가진채 메모리에 저장되게 된다.
char형 변수 a가 있고, a는 'A'라는 문자 하나를 담고 있다.
변수 a의 주소는 메모리에 26이라는 주소를 가진채 저장되었다.
그리고, char형 포인터 p를 선언하고, 포인터 p는 변수 a의 주소(26)를 가리킨다.
그림을 보면서 이해하면 더 쉬울 것이다.
그럼, 여기서
*p = 'B';
라는 명령을 주면 어떻게 될까?
포인터 p가 가리키는 값은 변수 a의 내용인 'A' 였지만,
위의 명령어는 포인터 p가 가리키는 값을 'B'로 변경하라는 명령어이기 때문에,
변수 a의 값이 'B'로 변경된 것을 알 수 있다.
포인터와 관련된 연산자
▶ & 연산자: 변수의 주소를 추출
▶ * 연산자: 포인터가 가리키는 곳의 내용을 추출
포인터의 종류도 여러가지가 있다.
포인터의 다양한 종류들 또한, 포인터는 필요할 때마다 형변환하여 사용하는 것이 가능하다.
포인터의 형변환 함수의 파라미터로서의 포인터
▶ 함수안에서 파라미터로 전달된 포인터를 이용하여 외부 변수의 값 변경 가능
포인터를 이용해 a와 b의 값을 변경하는 예제이다. 위 코드를 실행하면 a와 b의 값은 어떻게 나올까?
정답은 a = 2, b = 1이다.
main 함수 밖에서 파라미터를 통해 전달된 포인터를 이용하여 변수 a와 b의 값을 swap한 것이다.
그럼, 지금까지 공부한 내용과 결합하여 포인터를 사용해보자.
1) 배열
배열의 이름은 사실상 포인터와 같은 역할이다.
▶ 컴파일러가 배열의 이름을 배열의 첫 번째 주소로 대치
배열에서 포인터에 대한 사칙연산은 포인터가 가리키는 객체단위로 계산된다.
크기가 6인 int형 배열 A를 선언하고, int형 포인터 pi를 선언했다.
pi는 배열 A의 3번째 주소(22)를 가리킨다.
앞에서, 배열은 메모리상의 연속된 공간에 저장된다고 했는데,
주소가 4씩 띄워져 있는 이유는 C언어에서 일반적으로 int형 변수의 크기는 4byte이기 때문에 저렇게 표기되어 있는 것이다.
2) 구조체
구조체에서는 요소에 접근하기 위해 -> 라는 연산자를 사용한다.
아래의 예시를 보자.
먼저, int형 변수 i와, float형 변수 f를 담은 구조체를 선언하고,
구조체 변수를 s, 구조체의 포인터 변수를 ps로 선언하였다.
그리고, 포인터가 구조체 변수를 가리키도록 설정하고,
포인터를 사용하여 i 멤버에 접근하여 2로 설정하였고,
포인터를 사용하여 f 멤버에 접근하여 3.14로 설정하였다.
그림을 보면서 이해하면 더 쉬울 것이다.
포인터의 포인터
우리가 지금까지 배운 포인터는 어떠한 변수의 주소를 가리키고, 또 그 값을 저장한다고 배웠다.
하지만, 포인터도 자기가 가리키는 어떠한 변수의 값을 저장할 자신만의 주소값을 가진다.
즉, 포인터의 주소를 가리키는 포인터의 포인터를 선언할 수 있는 것이다.
이 개념은 추후 Linked List나 Tree, Graph에서 요긴하게 쓰이는 개념이라 알아두면 좋은 개념이다.
자체참조 구조체
필드중에 자기 자신을 가리키는 포인터가 한 개 이상 존재하는 구조체로, 연결 리스트(Linked List)나 트리(Tree), 그래프(Graph)에 많이 등장한다.
연결 리스트 구조체 포인터 사용시 주의할 점
1. 포인터가 아무것도 가리키고 있지 않을 때는 NULL로 설정해야 한다.
▶ int *pi = NULL;
2. 초기화가 안된 상태에서 사용 금지
pc 포인터의 초기화 실패 포인터를 초기화하지 않은 상태에서 사용하면, 메모리의 임의의 위치를 가리키게 되며,
이는 예기치 않은 동작이나 프로그램의 비정상적인 종료로 이어질 수 있기 때문에, 초기화를 반드시 진행해주고 사용한다.
3. 포인터 타입간의 변환 시에는 명시적인 타입 변환 사용
포인터 타입간의 명시적 형변환 동적 메모리 할당이란?
프로그램이 메모리를 할당받는 방법에는 정적 메모리, 동적 메모리 할당이 있다.
정적 메모리 할당
▶ 메모리의 크기는 프로그램이 시작하기 전에 결정
▶ 프로그램의 수행 도중에 그 크기가 변경될 수는 없다.
▶ 만약 처음에 결정된 크기보다 더 큰 입력이 들어온다면 처리하지 못할 것이고, 더 작은 입력이 들어온다면 남은 메모리 공간은 낭비될 것이다.
▶ (예) 변수나 배열의 선언
int buffer[100];
char name[] = "data structure";
동적 메모리 할당
▶ 프로그램의 실행 도중에 메모리를 할당 받는 것
▶ 필요한 만큼만 할당을 받고 또 필요한 때에 사용하고 반납
▶ 메모리를 매우 효율적으로 사용 가능
쉽게 말해, 메모리를 할당 받을 때, 고정된 값으로 할당을 받느냐, 필요한 만큼만 할당을 받느냐의 차이이다.
동적 메모리 할당 전형적인 동적 메모리 할당 코드는 동적 메모리 할당 -> 동적 메모리 사용 -> 동적 메모리 반납 순으로 이루어진다.
전형적인 동적 메모리 할당 코드 동적 메모리 할당 관련 라이브러리 함수
▶ malloc(int size) // 메모리 할당
size 바이트 만큼의 메모리 블록을 할당
malloc(int size) ▶ free(void ptr) // 메모리 할당 해제
ptr이 가리키는 할당된 메모리 블록을 해제
▶ sizeof(var) // 변수나 타입의 크기 반환(바이트 단위)
변수나 타입의 크기 반환(바이트 단위)
sizeof(var)의 예시 동적 메모리 할당 예제
#include <stdio.h> #include <stdlib.h> struct Example { int number; char name[10]; }; void main() { struct Example *p; p = (struct Example *)malloc(2*sizeof(struct Example)); if (p==NULL) { fprintf(stderr, "can't allocate memory\n"); exit(1); } p->number=1; strcpy(p->name,"Park"); (p+1)->number=2; strcpy((p+1)->name,"Kim"); free(p); }
Example 구조체에는 int형 변수 number와 10 크기의 char형 배열 name을 멤버로 가진다.
그리고, main함수에서 구조체의 포인터 변수 p를 선언하고,
malloc() 함수를 사용하여 struct Example 형의 요소를 두 개 저장할 수 있는 메모리 공간을 동적으로 할당한다.
sizeof(struct Example)는 struct Example의 크기를 바이트 단위로 반환하고, 곱하기 2를 함으로써
두 개의 요소를 저장할 수 있는 메모리 공간을 할당한다.
만약 포인터가 NULL이라면, 메모리 할당에 실패한 것이므로, 오류 메시지를 출력하고, 프로그램을 종료한다.
정상적으로 실행됐다면, p가 가리키는 메모리 공간에 있는 첫 번째 요소의 number에 1을, name에는 "Park" 문자를 저장한다.
p 다음에 있는 메모리 공간에 있는 두 번째 요소의 number에 2를, name에는 "Kim" 문자를 저장한다.
마지막에 free(p)를 사용함으로써, malloc() 함수를 사용하여 할당한 메모리 공간을 해제한다.
다음에 계속...
728x90'Data Structure' 카테고리의 다른 글
큐(Queue)란? (4) 2024.04.28 스택(Stack)이란? (0) 2024.04.27 구조체(Structure)란? (2) 2024.04.26 배열(Array)이란? (0) 2024.04.24 순환(Recursion)이란? (0) 2024.04.23