C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

저번 강의에서 함수의 매개변수로 포인터를 쓰는 법에 대해서 배웠습니다.

이번 강의에서는 포인터와 배열의 관계 알아보겠습니다.

​이번 강의는 [포인터가 뭔지는 아는 사람]과 [배열을 아는 사람]이 보기에 적합합니다.

※ 이 강의에서 사용하는 프로그래밍 언어는 C언어입니다. C언어의 기본 문법은 알고 있다는 가정하에 글이 작성될 예정입니다.

※ 후배를 가르친다는 컨셉으로 글을 쓸 것이기 때문에 정제되지 않은 말투로 쉽게 작성될 예정입니다. 따라서 표현의 오해가 있을 수 있으니 본문에서 이해가 안 가는 부분 있다면 댓글을 남겨주시면 감사하겠습니다.

※ 머릿속에 있는 내용을 생각나는 대로 작성될 예정입니다. 주관적이고 얕은 지식으로 쓰인 글이니 틀린 내용이나 다른 의견이 있다면 댓글을 남겨주시면 감사하겠습니다.

※ 그 외 건의사항이나 추가했으면 하는 내용도 알려주시면 감사하겠습니다.

배열 학습상태 확인

이번 강을 진행하기에 앞서 배열에서 짚고 넘어갈 부분을 체크해 보겠습니다.

배열의 이름은 배열의 시작 주소이다.

배열의 크기는 고정적이다.

배열의 크기는 자료형의 크기*요소의 개수이다.

위에 써놓은 말이 무슨말인지 모르겠다면... 배열을 다시 공부하시고 오길 바랍니다!

배열의 이름은 배열의 시작 '주소'

배열의 이름도 결국 주소를 나타내기 때문에 포인터 변수를 이용해 배열의 시작 주소를 저장할 수 있습니다.

위와 같은 배열이 있다고 가정해 봅시다.

메모리의 상태를 대략적으로 표현하면 다음과 같을 겁니다.

그리고 배열의 시작주소값를 대~충 1000이라고 가정합시다.

C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

배열의 대략적인 상태

포인터 변수는 주소를 저장하는 변수이므로 배열의 시작주소 또한 저장할 수 있습니다.

즉,아래와 같은 상황을 가능하다는 겁니다.

int arr[5]={1,2,3,4,5}; int *parr=arr; //arr: 배열의 이름 = 배열의 시작 주소

C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

포인터가 배열의 시작주소를 가리키는 상태

이 상태가 되면

parr을 배열 arr처럼 봐도 됩니다.

무슨말이나면

parr은 포인터지만 배열처럼

parr[1]

같이 배열처럼 인덱스를 사용할 수도 있고

그냥 배열arr에서 가능한건 parr도 다 가능하다는 소리입니다.

아 그래서 이게 뭐가 좋냐구요??

저도 사실 잘 모르겠습니다.

그냥 여기서는 '아 포인터랑 배열이 밀접한 관계가 있구나' , '포인터가 배열이 될 수 있구나' 정도만 알고 넘어 갑시다.

동적할당

킹적할당

포인터를 이용하면 원하는 만큼 메모리를 할당하여 배열처럼 사용할 수 있습니다.

그것을 [동적할당] 이라고 합니다.

배열에는 아주 대표적인 단점이 있습니다.

그것은 바로바로

배열의 크기를 선언할 때부터 정해줘야하고(정적할당) 그 정해진 크기는 불가변적 이라는 것입니다.

예를 들어

신입생의 정보를 저장하는 배열을 만들어야 하는 상황이 정해봅시다.

신입생이 몇명인지는 아직 모르는 상황이라서

대~충 배열의 크기를 1000으로 잡았습니다.

그런데 만약에 신입생이 한 300명 정도밖에 안됬다고 치면

700명 분의 메모리 낭비가 발생한 겁니다.

반대로 배열의 크기를 500정도 잡았는데 신입생이 700명 정도 된다면

아주 큰일이 나겠죠??

배열의 크기가 부족한건 큰 문제가 되기 때문에

우리는 보통 메모리의 낭비가 있더라도 배열의 크기를 넉넉하게 할당합니다.

하지만 동적할당을 이용하면 우리가 필요한 공간만큼만 배열을 할당할 수 있습니다.

먼저 동적할당을 하는 코드를 보겠습니다.

int n; int *arr; scanf("%d", &n); arr= (int*)malloc(sizeof(int) * n);

@.@

동적할당에서 핵심이 되는 함수는 malloc 함수 입니다.

malloc 은 Memory Allocation의 약자라고 보시면 외우기 쉬울겁니다.

함수의 이름에서 나타나 있듯이 malloc함수는 메모리를 할당해주는 함수입니다.

malloc 함수는 stdlib.h 헤더파일에 있는 라이브러리 함수이기 때문에

사용하기전에 #include <stdlib.h> 를 해줘야 합니다.

malloc함수는 '메모리를 얼마만큼' 할당해줄지를 인자로 넘겨주면 메모리를 할당해 줍니다.

위에 코드에서는 (sizeof(int) * n) 부분이 할당해줄 메모리의 크기를 나타냅니다. (int자료형의 크기 * 원소의 개수)

C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

동적할당을 하면 아래 그림과 같이 메모리에 프로그래머를 위한 공간을 마련해 줍니다.

C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

동적할당은 잘 됬으니

저 할당된 공간을 잘 쓰기만 하면 됩니다.

저 공간을 쓰려면 접근(참조)이 가능해야겠죠?

메모리에 대한 접근은 포인터를 통해 할 수 있으니

포인터 변수에 저 메모리의 시작주소를 저장해 준다면 사용할 수 있을것 같습니다.

그 시작주소는

malloc 함수가 저렇게 메모리를 할당해 준다음에 메모리의 시작주소를 리턴해줍니다.

이제 우리가 선언한 포인터 변수에 그 시작주소를 저장해주면

우리는 포인터 변수를 통해 동적할당된 배열에 접근이 가능해집니다.

즉, 동적할당된 배열을 쓸 수 있어집니다!

C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

int *arr = (int*)malloc(sizeof(int) * n);

C 포인터 배열 동적할당 - C pointeo baeyeol dongjeoghaldang

포인터 변수 arr에 동적할당된 배열의 시작 주소를 저장한 모양

주의사항 : 동적할당해제

포인터를 이용한 동적할당은 프로그램이 종료되기 전에 프로그래머가 직접 할당된 메모리를 해제해주어야 합니다.

배열같이 컴파일 당시에 할당된 메모리에 대해서는 운영체제가 알아서 메모리를 해제해 줍니다.

그러나 프로그램 실행도중 동적할당한 메모리에 대한 책임은 프로그래머에게 있습니다.

그래서 메모리 할당해제를 안해주고 프로그램을 종료시키면

동적할당된 배열이 메모리에 자리를 차지하고 있어서 컴퓨터 성능에 문제가 일어나죠.

어떻게 하냐구요?

정말 쉽습니다

free함수를 사용하면 됩니다.

free함수의 인자로 동적할당한 메모리의 시작주소(를 저장하고 있는 포인터 변수)를 인자로 넘겨주면 됩니다.

이번 강의에서는 동적할당에 대한 기초를 배웠습니다.

지금까지 포인터 강의에서는 int형 1차원 배열만을 예시로 들었는데요.

당연히 char, double등 모든 자료형에서 동적할당이 가능합니다.

그리고 2차원 배열또한 동적할당이 가능합니다.

2차원 배열의 동적할당은 쪼끔 어려울 수도 있기때문에 따로 포스팅을 하겠습니다.

이번에도 문제를 하나 내겠습니다.

다음 코드는 배열의 크기를 입력받아 정수배열을 동적으로 할당하고 배열의 원소를 모두 0으로 초기화하기 위한 코드입니다.

필요한 코드를 채워 넣어보세요.

#include <stdio.h> #include <stdlib.h> int main() { int size; int *score; printf("정수 배열의 크기 : "); scanf("%d", &size); /*동적할당 */ for(int i=0; i<size; i++){ /*배열 초기화 */ } /*동적할당 해제 */ return 0; }