Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- FND
- soc 설계
- gpio
- ATMEGA128A
- KEYPAD
- Pspice
- ring counter
- pwm
- prescaling
- dataflow modeling
- java
- Linked List
- vivado
- uart 통신
- structural modeling
- atmega 128a
- Edge Detector
- test bench
- stop watch
- hc-sr04
- behavioral modeling
- BASYS3
- LED
- D Flip Flop
- verilog
- Recursion
- Algorithm
- DHT11
- i2c 통신
- half adder
Archives
- Today
- Total
거북이처럼 천천히
배열 포인터 본문
1. 배열 요소의 주소와 배열의 주소
Q) 배열명은 "배열의 첫 번째 원소의 주소 값"을 의미하고 있음을 알고 있다. 그럼 &배열명 은 무엇을 의미하는가?
#include <stdio.h>
int main(void) {
int list[] = { 1, 2, 3, 4, 5 };
printf("list = %u\n", list);
printf("&list = %u\n\n\n", &list);
printf("list + 1 = %u\n", list + 1);
printf("&list + 1 = %u\n", &list + 1);
return 0;
}
- 위 실행 결과를 통해 알 수 있듯이 배열명인 list와 배열명의 주소인 &list는 동일한 주소 값을 갖는다.
- 하지만, 주소 덧셈 연산을 한 결과값은 전혀 다르다.
▶ list + 1 = list의 첫 번째 원소 주소값 + 4byte.
▶ &list + 1 = list의 첫 번째 원소 주소값 + (4byte * 5) = list의 첫 번째 원소 주소값 + 20byte - Q) 왜 동일한 배열에 대해서 서로 다른 결과값이 나오며, 결과값이 의미하는 것이 무엇인가?
- A) 배열도 사용자가 정의한 자료형이다. 따라서 이를 배열 관점에서 볼 수 도 있지만, 배열을 하나의 자료형으로도 볼수 있다. 따라서 &list + 1가 갖는 의미는 "list 배열 전체를 하나의 자료형으로 보았을 때, &list + 1 == '배열를 한 묶음' 으로 보고, 다음 주소 값을 반환한다.라고 볼 수 있다.
- list + 1 == list + sizeof(int) == list + 4
- &list + 1 == list + sizeof(list) == list + 20
2. 2차원 배열과 배열 포인터
Q) 1차원 배열명은 첫 번째 원소의 메모리 주소 값을 갖고 있다고 했다. 그럼 2차원 배열명은 어떤 원소, 요소의 수소 값을 갖고 있는가?
A) 2차원 배열명은 첫 번째 배열 요소(배열)의 주소를 가르킨다.
- 배열 포인터 (Array pointer) : 배열의 시작 주소를 저장하는 포인트 변수
- 주로 2차원 배열을 포인터에 저장하고 싶을 때, 사용한다.
- 다음 예시를 통해 살펴보자.
#include <stdio.h>
int main(void) {
// int 형 2차원 배열 생성
int board[][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
// 2차원 배열 board에 주소 연산자를 사용함으로서
// 배열이 가르키는 첫 요소의 주소 값을 얻는 동시에
// 배열 전체를 하나의 묶음으로 본다.
int(*p_board)[4] = &board;
// Print the board.
printf("Board = \n");
for (unsigned short row = 0; row < sizeof(board) / sizeof(board[0]); row++) {
for (unsigned short col = 0; col < sizeof(board[0]) / sizeof(board[0][0]); col++)
printf("%3d", p_board[row][col]);
printf("\n");
}
return 0;
}
코드 해석)
- Q) board 배열명이 가르키는 주소값은 무엇인가?
- board는 첫 번째 요소인 {1, 2, 3, 4}의 시작 주소를 가리키며, 좀 더 구체적으로 설명하면, board는 메모리에서 {1, 2, 3, 4}의 첫 번째 요소인 1이 저장된 메모리 위치를 가리키고 있다.
- Q) int (*p_board)[4] = &board; 가 갖는 의미는?
- &board : 배열명이 가르키는 첫 번째 요소의 주소 값을 의미하며,
배열 board를 하나의 묶음으로 보겠다는 것을 의미한다. - int (*p_board) [4] : 열의 갯수가 4인 2차원 배열의 주소 값을 포인터에 저장한다.
⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐
3. 주의) 포인터 배열과 배열 포인터의 차이
이 부분은 상당히 혼란을 야기할 수 있는 부분이기 때문에 정확하게 이해하고 넘어가자.
3-1) 정의
- 포인터 배열 : 배열의 각 원소들의 자료형이 포인터인 배열
- 배열 포인터 : 배열명이 가르키는 첫 번째 요소의 주소 값을 저장하는 포인터
3-2) 선언 (주의)
- 포인터 배열 : int *p_data [5]
- 배열 포인터 : int (*p_data)[4]
3-3) 활용
- 포인터 배열 : 2차원형태의 배열 생성하고 싶은 경우
- 배열 포인터 : 2차원 배열을 포인터 변수에 저장하고 싶은 경우
4. 배열 포인터의 활용 -
( 배열이 가르키는 주소 값을 포인터 변수에 저장한 뒤, 인자로 전달 )
#include <stdio.h>
// Function prototype.
void print_the_board(int(*p_board)[4], int max_row, int max_col);
// Main method
int main(void) {
int board[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {10, 11, 12, 13} };
int row = sizeof(board) / sizeof(board[0]);
int col = sizeof(board[0]) / sizeof(board[0][0]);
print_the_board(board, row, col);
return 0;
}
// Print the board.
void print_the_board(int(*p_board)[4], int max_row, int max_col) {
printf("Board = \n");
for (int row = 0; row < max_row; row++) {
for (int col = 0; col < max_col; col++)
printf("%5d", p_board[row][col]);
printf("\n");
}
}
- caller측에서 callee에게 2차원 배열을 argument 값으로 전달하면 callee측에선 2차원 배열을 넘겨 받기 위해 배열 포인터를 이용하여 받게 된다.
- 즉, caller 측에서 2차원 배열을 전달하면 calle 측에서는 배열 포인트을 통해 받을 수 있다.
4. Callee 측에서 2차원 배열을 받을 수 있는 방법에는 배열 포인터 말고 없는가?
이중 포인터로 받으면 안되는가?
#include <stdio.h>
// Function prototype.
void print_the_board(int** board, int max_row, int max_col);
// Main method
int main(void) {
int board[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int row = sizeof(board) / sizeof(board[0]);
int col = sizeof(board[0]) / sizeof(board[0][0]);
print_the_board(board, row, col);
return 0;
}
// Print the board
void print_the_board(int** board, int max_row, int max_col) {
for (int row = 0; row < max_row; row++) {
for (int col = 0; col < max_col; col++) printf("%5d", board[row][col]);
printf("\n");
}
}
- 작성자는 "꼭 Callee 측에서 2차원 배열을 받기 위해서는 배열 포인터를 사용하는가? 이중 포인터로도 받을 수 있지 않을까?"에 대한 궁금이 생겨서 위와 같이 코드를 작성하였다.
- 결론은 위와 같이 코드를 작성할 경우, 실행이 불가능하다.
- Q) callee 측에서 2차원 배열을 받기 위해서 parameter 값을 이중 포인터형태로 선언했는데, 왜 받을 수 없는가?
- ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐ ⭐
이중 포인터는 포인터의 주소 값을 저장하는 포인터이다. 만약 이중 포인터로 받고 싶다면 Caller 측에서 전달되는 arguement 값은 포인터의 주소 값이여야 할 것이다. 하지만, Caller 측에서 argument 값으로 전달하는 값은 무엇인가? Caller 측에서 argument 값으로 전달되는 값은 첫 번째 원소의 주소 값이다. - Q) 그럼, 2차원 배열을 Callee측에서 이중 포인터로 받기 위해서 어떻게 해야 하는가?
#include <stdio.h>
// Function prototype.
void print_the_board(int** board, int max_row, int max_col);
// Main method
int main(void) {
int board[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
int row = sizeof(board) / sizeof(board[0]);
int col = sizeof(board[0]) / sizeof(board[0][0]);
// 포인트 배열 선언
int* p_board[3];
for (int row = 0; row < 3; row++)
p_board[row] = board[row];
print_the_board(p_board, row, col);
return 0;
}
// Print the board
void print_the_board(int** board, int max_row, int max_col) {
for (int row = 0; row < max_row; row++) {
for (int col = 0; col < max_col; col++) printf("%5d", board[row][col]);
printf("\n");
}
}
- Caller 측에서 2차원 배열을 전달하는 것이 아닌 포인터 배열 형태로 전달하면 Callee 측에서 해당 포인트 배열을 받기 위해 2중 포인터로 받을 수 있다.
정리
Caller 측에서 Callee에게 2차원 배열을 전달하는 방법
- 2차원 배열을 전달하고 싶다면 Callee측에서 배열 포인트 형태로 받으면 된다.
- 포인트 배열을 전달하고 싶다면 Callee측에서 이중 포인터로 받으면 된다.
- 이중 포인터를 전달하고 싶다면 Callee측에서 이중 포인터로 받으면 된다.
(단, Callee 측에서 이중 포인터의 값을 수정하지 않는다는 전제하에)
'C' 카테고리의 다른 글
구조체의 메모리 공간 크기 (0) | 2024.06.20 |
---|---|
함수 포인터 (0) | 2024.06.19 |
이중 포인터 (1) | 2024.06.19 |
Pointer arry (포인터 배열) (0) | 2024.06.18 |
Register variable (0) | 2024.06.18 |