프로그래머스 입문 120842 2차원으로 만들기
문제
정수 배열 num_list를 앞에서부터 n개씩 끊어 2차원 배열로 만드시오.
num_list의 길이는 항상 n의 배수이므로 남는 원소는 고려하지 않는다.
| num_list | n | result |
|---|---|---|
| [1, 2, 3, 4, 5, 6, 7, 8] | 2 | [[1, 2], [3, 4], [5, 6], [7, 8]] |
| [100, 95, 2, 4, 5, 6, 18, 33, 948] | 3 | [[100, 95, 2], [4, 5, 6], [18, 33, 948]] |
풀이
문제 이름이 2차원으로 만들기인데 2차원 배열과 관련해서는 두 가지가 있다.
직사각형 배열(rectangular array)과 가변 길이 행 배열(jagged array)이다.
직사각형 배열(rectangular array)은 전체 원소가 하나의 연속된 메모리 블록에 놓이는 형태다.
result
|
v
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 7 | 8 | 9 |
+---+---+---+
가변 길이 행 배열(jagged array)은 포인터들이 연속해서 놓여 있고, 각 포인터가 따로 할당된 배열을 가리키는 형태다.
result
|
v
+----+ +---+---+---+
| *--+----> | 1 | 2 | 3 |
+----+ +---+---+---+
| *--+----> | 4 | 5 | 6 |
+----+ +---+---+---+
| *--+----> | 7 | 8 | 9 |
+----+ +---+---+---+
행마다 길이가 다르면 더 전형적인 가변 길이 행 배열의 모습이 된다.
result
|
v
+----+ +---+
| *--+----> | 1 |
+----+ +---+
+----+ +---+---+---+
| *--+----> | 2 | 3 | 4 |
+----+ +---+---+---+
+----+ +---+---+
| *--+----> | 5 | 6 |
+----+ +---+---+
+----+ +---+---+---+----+
| *--+----> | 7 | 8 | 9 | 10 |
+----+ +---+---+---+----+
행별 개별 할당으로 2차원 배열 만들기
#include <stdlib.h>
int** solution(int num_list[], size_t num_list_len, int n)
{
int col_count = n;
int row_count = num_list_len / col_count;
int** result = malloc(sizeof(*result) * row_count);
for (int row = 0; row < row_count; row++)
{
result[row] = malloc(sizeof(int) * col_count);
for (int col = 0; col < col_count; col++)
{
result[row][col] = num_list[row * col_count + col];
}
}
return result;
}
가독성을 위해 매개변수 n을 col_count에 담아 열 개수라는 의미를 드러냈다.
col_count는 한 행에 들어갈 원소 수이고, row_count는 전체 길이를 열 개수로 나눠 구한 행 개수다.
각 행의 주소를 저장하기 위해 result에는 행 개수만큼 공간을 할당한다.
이 공간은 행의 주소를 저장할 뿐, 각 행의 원소를 담는 공간은 아니다.
따라서 result[row]에는 한 행의 원소를 담을 공간을 따로 할당한다.
연속 메모리 블록을 행 포인터로 나누기
#include <stdlib.h>
#include <string.h>
int** solution(int num_list[], size_t num_list_len, int n)
{
int col_count = n;
int row_count = num_list_len / col_count;
int** result = malloc(sizeof(*result) * row_count);
int* data = malloc(sizeof(*data) * num_list_len);
memcpy(data, num_list, sizeof(*data) * num_list_len);
for (int row = 0; row < row_count; row++)
{
result[row] = data + row * col_count;
}
return result;
}
문제에서 반환형은 int**로 주어졌지만, 앞선 풀이와는 조금 다르게 접근해 볼 수 있다.
num_list를 하나의 연속된 메모리 블록에 복사하고, result에는 그 블록에서 col_count만큼씩 건너뛴 주소를 저장한다.
그러면 실제 값은 1차원으로 이어져 있어도, 접근 방식은 result[row][col]처럼 2차원 형태가 된다.
result
+----------+
0 | data + 0 | ----+
+----------+ |
1 | data + 3 | ----|-----------+
+----------+ | |
2 | data + 6 | ----|-----------|-----------+
+----------+ | | |
v v v
data +---+---+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8
^ ^ ^
| | |
result[0] result[1] result[2]
예를 들어 result[1]에는 data + 3이 저장되어 있다.
따라서 result[1][0]은 data[3]과 같고, 값은 4가 된다.
printf("%d\n", result[0][2]); // 3
printf("%d\n", result[1][0]); // 4
printf("%d\n", result[1][1]); // 5
printf("%d\n", *(result[1] + 1)); // 5