2023/2/16
동적할당을 이용하지 않고 배열을 생성하면 컴파일 단계 때 명확한 배열의 크기를 지정해주어야한다.
안정적으로 배열을 생성하기 위해서는 필요한 메모리의 양보다 넉넉하게 생성해 주어야 하는데, 이러한 넉넉함은 자원의 낭비를 불러 일으킬 수 있다.
위의 문제를 해결하기 위해 가변적으로 메모리를 할당할 수 있는 것이 동적할당이다.
#include <stdio.h>
#include <stdlib.h>
int main(int args, char **argv) {
int sizeOfArray;
int *arr;
scanf("%d", &sizeOfArray);
// malloc (memory allocation) 을 사용해 동적할당.
// stdlib 에 정의되어 있음으로 stdlib해더 파일 추가.
// malloc의 반환값은 할당한 메모리의 시작 주소
arr = (int*)malloc(sizeof(int) * sizeOfArray);
// use arr ...
// 할당한 메모리를 반환
// 적절하게 free를 해주지 않으면, 메모리 누수로 프로그램이 다운될 수 있다.
free(arr);
}
메모리의 Heap 영역에 생성.
#include <stuio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
int i, x, y;
int **arr;
scanf("%d %d", &x,&y);
arr = (int**)malloc(sizeof(int*) * x);
for(int i = 0 ; i< x ; i++){
arr[i] = (int*)malloc(sizeof(int) * y);
}
// use arr ...
for(int i = 0 ; i< x ; i++) {
free(arr[i]);
}
free(arr);
}
단 동적으로 생성된 포인터 배열은 2차원 배열이라고 단정 지을 수 없다.
포인터 배열의 2차원 배열의 동적할당은 메모리가 연속적으로 있다는 보장이 없기 때문이다.
때문에
int func(int **arr) {...}
의 함수의 매개변수로 사용할 수 있다.
2차원 배열처럼 행동하지만 사실은 int* 타입의 1차원 배열이다. (2차원 배열을 매개변수로 사용될 경우, 열의 정보를 알려주는 매개변수도 함께 전달되어야 했다)
메모리가 나란히 위치된 2차원 배열 동적할당.
int arr[height][width];
의 2차원 배열을 동적할당 하고 싶을 때, 할당되어야 하는 메모리의 크기는
height * width * sizeof(int)
int (*arr)[width] = (int(*)[width])malloc(height * width * sizeof(int));
2차원 배열 포인터의 경우, 포인터 연산을 수행하기 위해서는 반드시 포인터 타입 안에 행 길이가 들어가야한다.
위의 예시에서 컴파일러는 행의 크기가 width의 2차원 배열임을 알 수 있다.
#include <stdio.h>
#include <stdlib.h>
// 2차원 배열의 열을 지정해주어야 하기 때문에, 매개변수의 순서가 아래와 같게 하는 것이 중요하다.
void add_one(int width , int (*arr)[width], int height) {
for(int i = 0 ; i< height ; i++)
for(int j = 0 ; j < width ; j++)
arr[i][j]++
}
int main(){
int width, int height;
scanf("%d %d", &width, &height);
int (*arr)[width] = (int(*)[witdh])malloc(height * width * sizeof(int));
for(int i = 0 ; i< height ; i++){
for(int j =0 ; j< width ; j++){
scanf("%d" , &arr[i][j]);
}
}
print_array(width ,arr , height);
add_one(width, arr, height);
free(arr);
}
}
전자보다는 후자의 방법이 좋으다.