정적 2 차원 배열에 대한 포인터가 필요합니다. 어떻게하나요?
static uint8_t l_matrix[10][20];
void test(){
uint8_t **matrix_ptr = l_matrix; //wrong idea
}
다음과 같은 모든 종류의 오류가 발생합니다.
- 경고 : 호환되지 않는 포인터 유형에서 할당
- 아래 첨자 값은 배열도 포인터도 아닙니다.
- 오류 : 유연한 배열 구성원의 잘못된 사용
정적 2 차원 배열에 대한 포인터가 필요합니다. 어떻게하나요?
static uint8_t l_matrix[10][20];
void test(){
uint8_t **matrix_ptr = l_matrix; //wrong idea
}
다음과 같은 모든 종류의 오류가 발생합니다.
답변:
여기에서 배열의 첫 번째 요소에 대한 포인터를 만들고 싶습니다.
uint8_t (*matrix_ptr)[20] = l_matrix;
typedef를 사용하면 더 깔끔해 보입니다.
typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;
그러면 다시 인생을 즐길 수 있습니다 :)
matrix_ptr[0][1] = ...;
C 의 포인터 / 배열 세계 에 주의하세요.이 문제에 대해 많은 혼란이 있습니다.
주석 필드가 너무 짧아서 거기에서 할 수 없기 때문에 여기에서 다른 답변 중 일부를 검토하십시오. 여러 대안이 제안되었지만 어떻게 작동하는지는 표시되지 않았습니다. 방법은 다음과 같습니다.
uint8_t (*matrix_ptr)[][20] = l_matrix;
오류를 수정 &
하고 다음 스 니펫과 같이 주소 연산자를 추가하면
uint8_t (*matrix_ptr)[][20] = &l_matrix;
그런 다음 20 uint8_t 유형의 배열 요소의 불완전한 배열 유형에 대한 포인터를 만듭니다. 포인터는 배열의 배열을 가리 키기 때문에 다음을 사용하여 액세스해야합니다.
(*matrix_ptr)[0][1] = ...;
그리고 불완전한 배열에 대한 포인터이기 때문에 바로 가기로 할 수 없습니다.
matrix_ptr[0][0][1] = ...;
인덱싱은 요소 유형의 크기를 알려야하기 때문에 (인덱싱은 포인터에 정수 추가를 의미하므로 불완전한 유형에서는 작동하지 않습니다). 및 은 호환되는 유형 C
이므로 에서만 작동 합니다. C는 ++의 개념이없는 호환 유형을 , 그리고 그것은 그 코드를 거부합니다 때문에 그리고T[]
T[N]
T[]
T[10]
유형이 다르기 .
배열의 요소 유형, 당신은 1 차원 배열로 볼 때, 때문에 다음 대안은 전혀 일을하지 않는 없습니다 uint8_t
만,uint8_t[20]
uint8_t *matrix_ptr = l_matrix; // fail
다음은 좋은 대안입니다.
uint8_t (*matrix_ptr)[10][20] = &l_matrix;
당신은
(*matrix_ptr)[0][1] = ...;
matrix_ptr[0][0][1] = ...; // also possible now
외부 치수의 크기를 유지하는 이점이 있습니다. 그래서 당신은 그것에 sizeof를 적용 할 수 있습니다
sizeof (*matrix_ptr) == sizeof(uint8_t) * 10 * 20
배열의 항목이 연속적으로 저장된다는 사실을 활용하는 또 다른 답변이 있습니다.
uint8_t *matrix_ptr = l_matrix[0];
이제 공식적으로는 2 차원 배열의 첫 번째 요소의 요소에만 액세스 할 수 있습니다. 즉, 다음 조건이 유지됩니다.
matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid
matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior
에서 작동 할 수도 10*20-1
있지만 별칭 분석 및 기타 공격적인 최적화를 사용하면 일부 컴파일러가 해당 코드를 손상시킬 수 있다고 가정 할 수 있습니다. 그렇다고해서 실패하는 컴파일러를 본 적이 없으며 (하지만 실제 코드에서 해당 기술을 사용하지 않았습니다) C FAQ에도 해당 기술이 포함되어 있습니다 (UB'ness에 대한 경고 포함). ), 배열 유형을 변경할 수없는 경우 이것이 마지막으로 저장되는 옵션입니다. :)
uint8_t *d[20]
uint8_t에 대한 3 개의 포인터 배열을 생성하는 과 혼동했을 수 있지만이 경우에는 작동하지 않습니다.
에 완전히 이것을 이해, 당신은 해야합니다 다음 개념을 .
우선 (그리고 충분히 설교되었습니다) 배열은 포인터가 아닙니다 . 대신 대부분의 용도에서 포인터에 할당 할 수있는 첫 번째 요소의 주소로 '감쇠'합니다.
int a[] = {1, 2, 3};
int *p = a; // p now points to a[0]
나는 그것이 모든 것을 복사하지 않고 배열의 내용에 액세스 할 수 있도록 이렇게 작동한다고 가정합니다. 이는 배열 유형의 동작 일 뿐이며 동일한 것을 의미하지는 않습니다.
다차원 배열은 컴파일러 / 기계가 이해하고 작동 할 수있는 방식으로 메모리를 '분할'하는 방법 일뿐입니다.
예를 들어 int a[4][3][5]
= 정수 크기 메모리의 4 * 3 * 5 (60) '청크'를 포함하는 배열입니다.
int a[4][3][5]
일반 사용에 비해 장점int b[60]
은 이제 '파티션'(필요한 경우 '청크'로 작업하기 더 쉬움)되고 프로그램이 이제 경계 검사를 수행 할 수 있다는 것입니다.
사실, int a[4][3][5]
저장 정확히 같은 int b[60]
메모리 - 유일한 차이는 그들이 특정 크기의 별도의 엔티티를하는 경우로 프로그램이 지금 그것을 관리하는 것입니다 (특히, 오의 세 그룹의 네 그룹).
유의 사항 : 모두 int a[4][3][5]
와 int b[60]
메모리 같은이 있고, 유일한 차이점은이 응용 프로그램 / 컴파일러에 의해 처리하는 방법입니다
{
{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, 29, 30}
}
{
{31, 32, 33, 34, 35}
{36, 37, 38, 39, 40}
{41, 42, 43, 44, 45}
}
{
{46, 47, 48, 49, 50}
{51, 52, 53, 54, 55}
{56, 57, 58, 59, 60}
}
이로부터 각 "파티션"이 프로그램이 추적하는 배열이라는 것을 분명히 알 수 있습니다.
이제 배열은 포인터와 구문 론적으로 다릅니다 . 특히 이것은 컴파일러 / 머신이 그것들을 다르게 취급 할 것임을 의미 합니다. 이것은 생각할 필요가없는 것처럼 보일 수 있지만 다음을 살펴보십시오.
int a[3][3];
printf("%p %p", a, a[0]);
위의 예는 다음과 같이 동일한 메모리 주소를 두 번 인쇄합니다.
0x7eb5a3b4 0x7eb5a3b4
그러나 포인터에 직접 할당 할 수있는 것은 하나뿐입니다 .
int *p1 = a[0]; // RIGHT !
int *p2 = a; // WRONG !
a
포인터에 할당 할 수 없지만 할 수있는 이유는 무엇 a[0]
입니까?
이것은 간단히 말해서 다차원 배열의 결과이며 그 이유를 설명하겠습니다.
' a
' 수준 에서 우리는 여전히 기대할 또 다른 '차원'이 있음을 알 수 있습니다. a[0]
그러나 ' ' 수준 에서 우리는 이미 최상위 차원에 있으므로 프로그램에 관한 한 일반 배열 만보고 있습니다.
다음과 같이 질문 할 수 있습니다.
포인터를 만드는 것과 관련하여 배열이 다차원 인 경우 왜 중요합니까?
다음과 같이 생각하는 것이 가장 좋습니다.
다차원 배열의 '감쇠'는 단순한 주소가 아니라 파티션 데이터가있는 주소 (일명은 기본 데이터가 다른 배열로 구성되어 있음을 여전히 이해하고 있음)이며, 첫 번째 차원을 넘어서 배열에 의해 설정된 경계로 구성됩니다.
이 '파티션'로직은 지정하지 않는 한 포인터 내에 존재할 수 없습니다.
int a[4][5][95][8];
int (*p)[5][95][8];
p = a; // p = *a[0] // p = a+0
그렇지 않으면 배열 정렬 속성의 의미가 손실됩니다.
또한 주위에 괄호를 사용주의 *p
: int (*p)[5][95][8]
-의 우리가 이러한 경계, 이들의 경계를 가지는 포인터하지 배열에 대한 포인터를 만들고 있다는 것을 지정한다 :int *p[5][95][8]
재검토 해보자:
요약하자면 다차원 배열은 내용을 이해할 수있는 주소로 붕괴됩니다.
int *p1 = &(a[0]); // RIGHT !
, 실제로는 동일합니다int *p1 = a;
G'day,
선언
static uint8_t l_matrix[10][20];
20 개의 unit8_t 위치, 즉 200 개의 uint8_t 크기 위치의 10 개 행에 대한 스토리지를 따로 설정했으며 각 요소는 20 x 행 + 열을 계산하여 찾습니다.
그래서하지 않습니다
uint8_t (*matrix_ptr)[20] = l_matrix;
필요한 것을 제공하고 배열의 첫 번째 행의 열 0 요소를 가리 킵니까?
편집 : 이것에 대해 조금 더 생각하면 배열 이름이 정의에 따라 포인터가 아닙니까? 즉, 배열의 이름은 첫 번째 요소의 위치에 대한 동의어입니다. 즉, l_matrix [0] [0]?
Edit2 : 다른 사람들이 언급했듯이 댓글 공간은 추가 논의를하기에는 너무 작습니다. 어쨌든:
typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;
해당 어레이에 대한 스토리지 할당을 제공하지 않습니다.
위에서 언급하고 표준에 정의 된대로 다음과 같은 진술이 있습니다.
static uint8_t l_matrix[10][20];
uint8_t 유형의 200 개의 순차적 위치를 따로 설정했습니다.
다음 형식의 문을 사용하여 l_matrix 참조 :
(*l_matrix + (20 * rowno) + colno)
rowno 행에있는 colno'th 요소의 내용을 제공합니다.
모든 포인터 조작은 가리키는 개체의 크기를 자동으로 고려합니다. -K & R 섹션 5.4, p.103
패딩이나 바이트 정렬 시프트가 객체 저장에 관여하는 경우에도 마찬가지입니다. 컴파일러는이를 자동으로 조정합니다. C ANSI 표준의 정의에 따라.
HTH
건배,
C99 (clang 및 gcc에서 지원)에는 참조를 통해 다차원 배열을 함수에 전달하는 모호한 구문이 있습니다.
int l_matrix[10][20];
void test(int matrix_ptr[static 10][20]) {
}
int main(void) {
test(l_matrix);
}
일반 포인터와 달리 이것은 배열 크기에 대한 힌트를 제공 하여 이론적으로 컴파일러가 너무 작은 배열을 전달하는 것에 대해 경고하고 명백한 범위를 벗어난 액세스를 발견 할 수 있도록합니다.
안타깝게도 수정되지 않고 sizeof()
컴파일러가 아직 해당 정보를 사용하지 않는 것 같으므로 여전히 호기심이 많습니다.
static 10
한다는 일종의 보증입니다 . 다시 말해서 크기가 고정되지 않았 음을 의미합니다.
static
가 없으면 배열이 참조로 전달되지 않으며 사실이 아닙니다. 어쨌든 배열은 참조로 전달됩니다. 원래 질문은 동일한 함수 / 네임 스페이스 내에서 보조 포인터를 사용하여 2D 배열의 요소에 액세스하는 다른 사용 사례에 대해 질문했습니다.
배열을 선형으로 선언하고 (row, col)에서 배열 인덱스 계산을 직접 수행하여 컴파일러를 다루지 않아도됩니다.
static uint8_t l_matrix[200];
void test(int row, int col, uint8_t val)
{
uint8_t* matrix_ptr = l_matrix;
matrix_ptr [col+y*row] = val; // to assign a value
}
이것은 컴파일러가 어쨌든 한 일입니다.
다차원 배열을 가리키는 포인터를 초기화하는 기본 구문은 다음과 같습니다.
type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name
그것을 호출하는 기본 구문은 다음과 같습니다.
(*pointer_name)[1st index][2nd index][...]
다음은 예입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// The multidimentional array...
char balance[5][100] = {
"Subham",
"Messi"
};
char (*p)[5][100] = &balance; // Pointer initialization...
printf("%s\n",(*p)[0]); // Calling...
printf("%s\n",(*p)[1]); // Calling...
return 0;
}
출력은 다음과 같습니다.
Subham
Messi
작동했습니다 ...
다음과 같이 할 수 있습니다.
uint8_t (*matrix_ptr)[10][20] = &l_matrix;