본문 바로가기
C/코딩도장

[코딩도장] Unit 38. 포인터와 배열 응용하기

by 단월໒꒱ 2021. 7. 24.

1. 포인터와 배열 응용하기

 

int numArr[10]; 처럼 고정된 크기로 배열 생성 가능하지만 int numArr[size]; 처럼 크기를 동적으로 지정할 수 없다.

 

따라서 배열의 크기를 동적으로 지정하려면 포인터를 선언하고 메모리를 할당한 뒤 메모리를 배열처럼 사용해야 한다.

 

2. 포인터에 할당된 메모리를 배열처럼 사용하기

 

포인터를 배열처럼 사용하려면 포인터에 malloc 함수로 메모리를 할당해주면 된다.

 

자료형 *포인터이름 = malloc(sizeof(자료형) * 크기);

 

배열과 메모리가 할당된 포인터는 생성 방법만 다르고 값을 다루는 방법은 같다.

*numPtr처럼 포인터를 역참조한 것과 numPtr[0] 같은 값을 가져온다.

*(numPtr + 1) 역참조한 것과 numPtr[1] 같은 값을 가져온다.

이렇게 포인터에 값을 더하는 방식을 포인터 연산이라고 

 

 

3. 입력한 크기만큼 메모리를 할당하여 1차원 배열처럼 사용하기

 

 

크기를 입력해서 메모리를 할당한 뒤 입력받은 크기만큼 반복하면서 값을 할당하고,

다시 입력받은 크기만큼 반복하면서 값을 출력한다.

 

배열과 마찬가지로 메모리가 할당된 포인터는 값을 할당하거나 출력할 때 [  ]를 사용해서 인덱스로 접근한다.

 

4. 포인터에 할당된 메모리를 2차원 배열처럼 사용하기

 

1) 자료형 **포인터이름 = malloc(sizeof(자료형 *) * 세로크기); 와 같이 세로 공간 메모리 할당

2) 반복문으로 반복하면서 포인터[i] = malloc(sizeof(자료형) * 가로크기); 와 같이 가로 공간 메모리 할당

3) 반복문으로 반복하면서 free(포인터[i]);와 같이 가로 공간 메모리 해제

4) free(포인터);와 같이 세로 공간 메모리 해제

 

 

먼저 이중 포인터에 2차원 배열의 세로 공간에 해당하는 메모리를 할당한다.

이때, 세로 공간에는 값이 들어가지 않고 가로 공간의 메모리 주소가 들어간다.

따라서 sizeof(int)가 아니라 sizeof(int *)처럼 포인터의 크기를 구한 다음에 세로크기를 곱해준다.

* 32비트에서는 int나 int * 크기가 4바이트, 64비트에서는 int는 4바이트, int *는 8바이트이므로 포인터가 들어갈 공간이란 걸 확실히 구분해줘야 한다.

 

세로 크기 만큼 반복하면서 2차원 배열의 가로 공간에 해당하는 메모리를 할당한다.

가로 공간에는 int형 숫자가 들어갈 것이므로 sizeof(int)에 가로크기를 곱해준다.

이렇게 하면 2차원 배열 사용하듯이 포인터[세로인덱스][가로인덱스] 에 값을 할당하거나 가져올 수 있다.

 

* 메모리 해제 시 주의!

메모리 할당할 때 세로 -> 가로 순서로 할당했으므로 해제할 때는 반대로 가로 -> 세로 순으로 해제한다.

세로 공간에 해당하는 메모리를 먼저 해제하면 가로 공간 메모리를 해제할 수 없게 된다.

 

5. 입력한 메모리 크기만큼 메모리를 할당하여 포인터를 2차원 배열처럼 사용하기

 

 

위의 코드처럼 사용자가 입력한 가로, 세로의 크기만큼 메모리를 할당하고 이를 바탕으로 포인터를 2차원 배열로 사용할 수 있다.

가로, 세로의 크기는 사용자가 결정하므로 반복문 작성시 숫자 대신 사용자가 입력할 수를 받을 row와 col을 이용하도록 한다.

마찬가지로 메모리 해제는 가로 -> 세로 순으로 진행한다.

 

 

# 연습문제

 

다음 소스 코드를 완성하여 포인터에 할당된 메모리를 높이 2, 세로 크기 3, 가로 크기 5인 3차원 배열처럼 사용할 수 있도록 만드세요.

 

[코드 및 결과]

 

 

[설명]

6번째 줄에서 먼저 삼중 포인터를 선언해주고 높이가 2인 공간을 만들어주었다.

이 후의 내용이 비어있기 때문에 차례로 세로와 가로 공간에 해당하는 메모리를 할당해주었다.

그리고 printf 함수로 배열을 출력함으로써 메모리 사용이 끝났으니 아래는 메모리를 해제하는 내용일 것이라 생각했다.

따라서 반복문을 통해 가로와 세로를 먼저 해제해주었고 마지막으로 높이에 해당되는 메모리를 해제해주었다.

 

 

# 심사문제  1

 

 

[코드 및 결과]

 

 

[설명]

scanf 함수로 정사각형의 가로/세로 크기인 size를 입력 받도록 했다.

이 행렬을 출력하도록 하려면 2차원 배열을 반들어야 하는데, 그러면 이중 포인터에 메모리를 할당해야 한다.

matrix라는 배열을 만들어주고 **를 통해 이중 포인터로 선언해주었다.

먼저 세로 공간에 메모리를 할당해준 뒤에 아래 for문을 통해 입력받은 size만큼 반복하면서 가로 공간에 해당하는 메모리를 할당해줬다.

문제에서 얘기한 단위행렬의 정의에 따라 가로, 세로의 위치가 같으면 1, 아니면 0을 출력하도록 각각의 값을 할당해주었다.

그 후 printf 함수로 2차원 배열에 저장된 값을 출력하도록 했다.

마지막으로 가로 공간의 메모리를 해제해준 뒤 세로 공간의 메모리를 해제해주었다.

 

 

# 심사문제 2

 

 

[코드 및 결과]

 

 

[설명]

scanf 함수로 세로, 가로의 크기를 입력 받고 이중 포인터를 사용하여 입력 받은 가로, 세로의 크기만큼 메모리를 할당했다.

이때, 12번째 줄에서 (col + 1)만큼 곱해주었는데, 이는 나중에 덧붙일 \n의 자리 때문에 1을 더 더해준 것이다.

메모리를 할당한 뒤 memset 함수로 0으로 초기화해주었다.

세로와 가로 순서대로 반복문을 중첩시켜서 *인 경우는 * 그대로, 아닌 경우는 주변을 탐색해서 지뢰인 *의 위치를 파악한 뒤 count에 +1을 더하도록 해주었다.

이렇게 count에 저장된 수를 ms[i][j]에 저장하고 다시 count를 0으로 초기화시킨 후 위의 과정을 반복하도록 했다.

마지막으로 가로 공간의 메모리를 해제한 뒤, 세로 공간의 메모리를 해제해주었다.

댓글