对于传递一维数组,请在此处查看我的其他答案:Passing an array as an argument to a function in C
TLDR;
直接跳下来,查看“结论和建议摘要...”部分下的 4 个打印示例。
如何在 C 和 C++ 中使用多维(例如:2D)数组和指向它们的指针作为函数参数
对于包括我自己在内的几乎所有人来说,多维数组都非常令人困惑——对于有经验的程序员和初学者来说都是如此。因此,我想提供一组规范的示例,我可以一遍又一遍地回顾和参考(但是,请参阅此答案下方的 cmets;我并没有涵盖所有内容),并带有一些清晰的演示和易于-遵循指导方针。就这样吧。
前言:
-
注意:从 C2x(C20 或更高版本)开始,以下“原始原则”准则 15 生效(来源:Wikipedia: C2x --> 原始来源:Programming Language C - C2x Charter):
-
应用程序编程接口 (API) 应尽可能自行记录。 特别是,应安排函数声明中的参数顺序,以使数组的大小出现在数组之前。目的是允许使用可变长度数组 (VLA) 表示法。这不仅使人类读者更清楚代码的用途,而且使静态分析更容易。添加到标准中的任何新 API 都应考虑到这一点。
所以,如果您想符合 C2x(迄今为止大多数标准 C 函数不符合),那么请重新排列我下面的所有函数,以将数组大小参数放在 之前数组或指向数组的参数。
-
我开始回答这个问题是为了回答这个问题:Passing a pointer to array to my function。但是,它更适合这里,所以我把它放在这里。
-
下面的代码可以在我的eRCaGuy_hello_world repo 中找到:c/2d_array_practice.c。它在 C 和 C++ 中编译和运行(在 C11 和 C++17 中测试)。请参阅源代码文件顶部的构建和运行命令。为了安全起见,我使用 gcc 构建选项 -Wall -Wextra -Werror。
-
我的答案集中在多维 2D 数组,但可以轻松扩展到任意数量的维度:3D、4D、5D 等...ND 数组。
-
我在打印函数中使用const,因为我只是打印数组而不是修改它们。如果您需要就地修改数组,请删除 const。
首先要注意的数组注意事项:
-
固定尺寸与未指定尺寸:
数组必须在所有维度上固定(指定)大小,第一个(最外层)维度除外,可以选择未指定。
// OK; 1D array with unspecified 1st (and only) dimension
int array[] = {1, 2, 3};
// OK; 2D array with unspecified 1st dimensions
int array[][2] = {{1, 2}, {3, 4}};
// NOT allowed; 2D array with both dimensions unspecified!:
// `error: array type has incomplete element type ‘int[]’`
int array[][] = {{1, 2}, {3, 4}};
-
数组类型的自然类型衰减:
首先,让我区分“数组类型”和“指向数组类型的指针”。 “数组类型”是数组,“指向数组类型的指针”是指针。指针不能衰减到(AKA“调整”成为)指针,因为它们是已经的指针。然而,数组可以并且确实衰减为(“调整”为)指针。
(1) 所以,这里有一些数组类型的例子,意味着它们只是普通的“数组”:int array_2d[][2], int* array_2d[], int array_2d[3][2] .第一个是二维整数数组,第二个是一维数组int*,第三个是二维整数数组。
(2) 但是,这是一个指向数组类型的指针,或“指向数组的指针”:int (*array_2d)[3][2]。数组的 ptrs 总是在星号周围有括号,如下所示:(*),就在方括号之前。这样你才能认出它们。因此,上面的前 3 个数组在用作参数时会衰减为 ptrs,而最后一个则不会,因为它已经是一个 ptr。
原理是:当用作函数参数时,所有数组类型(但不是数组类型的ptrs)将第一个维度衰减为一个ptr,无论该维度是大小是否明确指定!因此,尽管int arr[](整数数组)和int * arr(指向整数的指针)不是同一类型,但其中任何一个的函数定义都会自然衰减数组中的第一个维度(这是唯一的在一维数组情况下的维度)向下到一个指针,导致在两种情况下都将类型(int * arr)传递给函数:
// accepts `int *` as `array` parameter
void my_func(int * array, size_t len) {}
// also accepts `int *` as `array` parameter, since the `int []` type
// (array of ints) naturally decays down to type `int *` (ptr to int`).
void my_func(int array[], size_t len) {}
更进一步,将大小指定为数组的第一个维度与此效果无关。即:它没有任何区别,对编译器毫无意义。它只是作为一个视觉指示器或“自我文档”类型程序员就是这样,这个特定的函数需要一个至少这个大小或更大的数组。请在此处查看我的回答 (Passing an array as an argument to a function in C),其中我谈到了这一点,并引用了 MISRA-C 标准,该标准建议将此功能用于自我记录目的。
所以,这些都和上面的函数一样:
// same as above: these ALL accept `int *` as the 1st parameter, and the
// specified size here in square brackets [] has no effect on the compiler.
void my_func(int array[1], size_t len) {}
void my_func(int array[10], size_t len) {}
void my_func(int array[100], size_t len) {}
所以,这很好:
int array[10];
my_func(array); // ok; `array` naturally decays down to type `int *`
这也很好:
int array[10];
int * array_p = array;
my_func(array_p); // ok; is already of type `int *`
但是,对于 指向数组的指针,实际的数组类型和大小确实很重要,并且不会发生从数组到 ptr 的自然类型衰减,因为类型已经一个ptr——指向一个指定类型和大小的数组!阅读my answer above。
示例:以下函数需要一个 ptr 类型的输入参数到大小为 10 的一维数组。它已经是一个ptr,所以不会发生自然类型衰减到一个ptr!由于这个参数是一个数组的ptr,你必须在创建函数时也通过&字符传递数组的地址调用,如下图。请注意,以下调用中只有 2 个有效:my_func(&array2); 和 my_func(array2_p2);。然而,我努力展示了所有这些调用,以便能够解释和演示各种数组类型以及它们如何以及何时衰减为指针,以及什么类型。
// 0. Define a function
/// `array` is a "ptr to an array of 10 ints".
void my_func(int (*array)[10]) {}
// 1. Create arrays
int array1[5];
int *array1_p = array1; // array1_p is of type `int *` (ptr to int)
int (*array1_p2)[5] = &array1; // array1_p2 is of type `int (*)[5]` (ptr
// to array of 5 ints)
int array2[10];
int *array2_p = array2; // array2_p is of type `int *` (ptr to int)
int (*array2_p2)[10] = &array2; // array2_p2 is of type `int (*)[10]` (ptr
// to array of 10 ints)
// 2. Make some calls
// 2.1. calling with `int array1[5]`
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to **natural type decay** from
// `int[5]` (array of 5 ints) to `int *` (ptr to int)
my_func(array1);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to dereferencing to `int[5]` (array
// of 5 ints), followed by **natural type decay** from `int[5]`
// (array of 5 ints) to `int *` (ptr to int)
my_func(*array1_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int)
my_func(array1_p);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`; due to **natural type decay** from `int[5]` (array of
// 5 ints) to `int *` (ptr to int), in conjunction with dereferencing
// from that to `int`
my_func(*array1);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`
my_func(*array1_p);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (*)[5]` (ptr to array of 5 ints)
my_func(&array1);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (*)[5]` (ptr to array of 5 ints)
my_func(array1_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (**)[5]` (ptr to "ptr to array of 5 ints")
my_func(&array1_p2);
// 2.2. calling with `int array2[10]`
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to **natural type decay** from
// `int[10]` (array of 10 ints) to `int *` (ptr to int)
my_func(array2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int); due to dereferencing to `int[10]` (array
// of 10 ints), followed by **natural type decay** from `int[10]`
// (array of 10 ints) to `int *` (ptr to int)
my_func(*array2_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int *` (ptr to int)
my_func(array2_p);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`; due to **natural type decay** from `int[10]` (array of
// 10 ints) to `int *` (ptr to int), in conjunction with dereferencing
// from that to `int`
my_func(*array2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int`
my_func(*array2_p);
// <===============
// <=== WORKS! ====
// <===============
// Expected and received `int (*)[10]` (ptr to array of 10 ints)
my_func(&array2);
// <===============
// <=== WORKS! ====
// <===============
// Expected and received `int (*)[10]` (ptr to array of 10 ints)
my_func(array2_p2);
// FAILS! Expected `int (*)[10]` (ptr to array of 10 ints) but argument is
// of type `int (**)[10]` (ptr to "ptr to array of 10 ints")
my_func(&array2_p2);
-
指针快速提醒:
请记住,int *[2] 和 int (*)[2] 类型不是同一类型!括号很重要! int *[2] 是“2 个 int *s 的数组(指向 int 的指针)”,而 int (*)[2] 是“指向 2 个 ints 的数组的指针”。这是两个非常不同的东西。
另外,ptr 可以像数组一样被索引,这会导致经常混淆数组是一个ptr,这是错误的。数组不是 ptr!但是,以下概念对于理解下面的代码至关重要:int array_2d[][2] 是一个二维数组。变量array_2d 的类型为int [][2](n x 2 (2D) 整数数组),它是具有未指定行数(维度 1)和 2 列(维度 2)的二维数组。当用作函数参数时,此int [][2] 类型自然衰减 类型int (*)[2](ptr 到 2 个整数的 (1D) 数组)。那么,如果这个衰减的类型是一个ptr,它怎么还是一个数组呢?好吧,既然 ptr 可以像数组一样被索引,你仍然可以这样做来索引它:array_2d[row][col]。外部维度是 ptr,可索引为 row,而内部维度是 [2](2 个整数)部分,可索引为 column,因为它是数组中的子数组.这意味着每行包含 2 个整数,因此一旦您索引到 row,您就需要索引到 column。因此,ptrs 和数组之间的混淆在于 所有 ptr 都可以像数组一样索引,即使 数组不是 ptrs——而是第一个维度当用作参数时,所有数组(但不是数组的指针)衰减为一个指针。
因此,考虑到上述概念,以下内容会更有意义。对于每一个函数定义,注意数组类型是什么,会不会自然衰减,具体是什么。同样,当用作函数参数时,所有 非指针 数组类型都会将数组的第一个维度向下衰减为 ptr,它仍然像数组一样可索引。
关于传递多维数组的结论和建议总结:
以下是我将多维数组作为参数传递的 4 个用例和技术,以及何时使用它们的建议。 您可以从每种技术的函数原型和定义中看到每种技术提供的不同权衡、复杂性和优势。
假设您有以下二维数组:
int arr[][2] =
{
{1, 2},
{5, 6},
{7, 8},
};
...以及以下宏定义:
// Get the number of elements in any C array
// - from my repo here:
// https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/utilities.h#L42
#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
/// Definitions: `rows` = "rows"; `cols` = "columns"
/// Get number of rows in a 2D array
#define NUM_ROWS(array_2d) ARRAY_LEN(array_2d)
/// Get number of columns in a 2D array
#define NUM_COLS(array_2d) ARRAY_LEN(array_2d[0])
- 固定大小的多维数组:如果 2D 数组每次总是相同的大小(它有 FIXED 行数和 FIXED 列数)(3 行和 2以下示例中的列),请执行以下操作:
// 1. Function definition
/// \brief Print a 2D array which has a FIXED number of rows and
/// FIXED number of columns.
/// \param[in] array_2d a 2D array; is of type `int (*)[3][2]` (ptr to
/// 3 x 2 (2D) array of ints); since it is already
/// explicitly a ptr, it does NOT naturally decay to
/// any other type of ptr
/// \return None
void print_array2(const int (*array_2d)[3][2])
{
printf("print_array2:\n");
for (size_t row = 0; row < NUM_ROWS(*array_2d); row++)
{
for (size_t col = 0; col < NUM_COLS(*array_2d); col++)
{
printf("array_2d[%zu][%zu]=%i ", row, col, (*array_2d)[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
// NB: `&` is REQUIRED! See my answer for why: https://stackoverflow.com/a/51527502/4561887
print_array2(&arr);
// 3. Usage via a pointer
// `int (*array_2d)[3][2]` is an explicit ptr to a 3x2 array of `int`. This
// pointer to an array does NOT naturally decay to a simpler type.
int (*p2)[3][2] = &arr; // must use `&` and MUST USE THESE PARENTHESIS!
print_array2(p2);
- 如果二维数组的行数是可变的,但列数是固定的(在本例中为 2),
做这个:
// 1. Function definition
/// \brief Print a 2D array which has a VARIABLE number of rows but
/// FIXED number of columns.
/// \param[in] array_2d a 2D array; is of type `int [][2]` (n x 2 (2D) array
/// of ints), which naturally decays to type
/// `int (*)[2]` (ptr to (1D) array of 2 ints)
/// \param[in] num_rows The number of rows in the array
/// \return None
void print_array3(const int array_2d[][2], size_t num_rows)
{
printf("print_array3:\n");
// Technique 1: use `array_2d` directly.
printf("--- Technique 1: ---\n");
for (size_t row = 0; row < num_rows; row++)
{
for (size_t col = 0; col < NUM_COLS(array_2d); col++)
{
printf("array_2d[%zu][%zu]=%i ", row, col, array_2d[row][col]);
}
printf("\n");
}
// Technique 2: cast the `array_2d` decayed ptr to a ptr to a sized array of
// the correct size, then use that ptr to the properly-sized array
// directly! NB: after obtaining this ptr via the cast below, this
// technique is **exactly identical** to (I copy/pasted it from, then
// renamed the variable) the implementation inside `print_array2()` above!
printf("--- Technique 2: ---\n");
int (*array_2d_ptr)[num_rows][NUM_COLS(array_2d)] =
(int (*)[num_rows][NUM_COLS(array_2d)])array_2d;
for (size_t row = 0; row < NUM_ROWS(*array_2d_ptr); row++)
{
for (size_t col = 0; col < NUM_COLS(*array_2d_ptr); col++)
{
printf("array_2d_ptr[%zu][%zu]=%i ", row, col, (*array_2d_ptr)[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
print_array3(arr, NUM_ROWS(arr));
// 3. Usage via a pointer
// `int array_2d[][2]` (n x 2 (2D) array of ints) naturally decays to
// `int (*)[2]` (ptr to (1D) array of 2 ints)
int (*p3)[2] = arr; // MUST USE THESE PARENTHESIS!
print_array3(p3, NUM_ROWS(arr));
- 如果二维数组有可变的行数和可变的列数,请执行此操作(
方法是最通用的,因此通常是我的整体首选方法,也是多维数组的首选方法):
// 1. Function definition
/// \brief Print a 2D array which has a VARIABLE number of rows and
/// VARIABLE number of columns.
/// \param[in] array_2d a 2D array; is of type `int *` (ptr to int); even
/// though a 1D array of type `int []` (array of ints)
/// naturally decays to this type, don't think about it
/// that way; rather, think of it as a ptr to the first
/// `int` in a contiguous block of memory containing a
/// multidimensional array, and we will manually index
/// into it as required and according to its dimensions
/// \param[in] num_rows The number of rows in the array
/// \param[in] num_cols The number of columns in the array
/// \return None
void print_array4(const int *array_2d, size_t num_rows, size_t num_cols)
{
printf("print_array4:\n");
// Technique 1: use `array_2d` directly, manually indexing into this
// contiguous block of memory holding the 2D array data.
printf("--- Technique 1: ---\n");
for (size_t row = 0; row < num_rows; row++)
{
const int *row_start = &array_2d[row*num_cols];
for (size_t col = 0; col < num_cols; col++)
{
// NB: THIS PART IS VERY DIFFERENT FROM THE OTHERS! Notice `row_start[col]`.
printf("array_2d[%zu][%zu]=%i ", row, col, row_start[col]);
}
printf("\n");
}
// Technique 2: cast the `array_2d` decayed ptr to a ptr to a sized array of
// the correct size, then use that ptr to the properly-sized array
// directly! NB: after obtaining this ptr via the cast below, this
// technique is **exactly identical** to (I copy/pasted it from, then
// renamed the variable) the implementation inside `print_array2()` above!
printf("--- Technique 2: ---\n");
int (*array_2d_ptr)[num_rows][num_cols] =
(int (*)[num_rows][num_cols])array_2d;
for (size_t row = 0; row < NUM_ROWS(*array_2d_ptr); row++)
{
for (size_t col = 0; col < NUM_COLS(*array_2d_ptr); col++)
{
printf("array_2d_ptr[%zu][%zu]=%i ", row, col, (*array_2d_ptr)[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
print_array4((int *)arr, NUM_ROWS(arr), NUM_COLS(arr));
// OR: alternative call technique:
print_array4(&arr[0][0], NUM_ROWS(arr), NUM_COLS(arr));
// 3. Usage via a pointer
// The easiest one by far!
int *p4_1 = (int*)arr;
// OR
int *p4_2 = &arr[0][0];
print_array4(p4_1, NUM_ROWS(arr), NUM_COLS(arr));
print_array4(p4_2, NUM_ROWS(arr), NUM_COLS(arr));
但是,如果您有以下“2D”数组,则必须做一些不同的事情:
// Each row is an array of `int`s.
int row1[] = {1, 2};
int row2[] = {5, 6};
int row3[] = {7, 8};
// This is an array of `int *`, or "pointer to int". The blob of all rows
// together does NOT have to be in contiguous memory. This is very different
// from the `arr` array above, which contains all data in contiguous memory.
int* all_rows[] = {row1, row2, row3}; // "2D" array
- 如果二维数组实际上是由一堆指向其他数组的 ptr 构成的(如上所示),
做这个:
// 1. Function definition
/// \brief Print a 2D-like array, where the array passed in is an array of
/// ptrs (int *) to other sub-arrays. Each index into the outer
/// array is the row, then each index into a sub-array in a given
/// row is the column. This handles a VARIABLE number of rows and
/// VARIABLE number of columns.
/// \details `array_2d` here is different from all of the cases above. It is
/// NOT a contiguous 2D array of `int`s; rather, it is an array of
/// pointers to ints, where each pointer in the array can be
/// thought of as a sub-array. Therefore, the length of the outer
/// array is the number of rows, and the length of each sub-array,
/// or inner array, is the number of columns. Each sub-array
/// (a single row of `int`s) DOES have to be in contiguous memory,
/// and the array of _pointers_ DOES have to be in contiguous
/// memory, but the total _storage space_ for the combined total of
/// all rows can be in NON-contiguous memory. Again, this is VERY
/// different from every other function above.
/// \param[in] array_2d a 2D array; is of type `int * []` (array of ptrs to
/// int) (where each ptr is a sub-array of ints);
/// `int * []` naturally decays to type `int**` (ptr to
/// "ptr to int")
/// \param[in] num_rows The number of rows in the array (number of elements
/// in the `array_2d` outer array)
/// \param[in] num_cols The number of columns in the array (number of
/// elements in each sub-array)
/// \return None
void print_array5(const int* array_2d[], size_t num_rows, size_t num_cols)
{
printf("print_array5:\n");
printf("--- Technique 1: use `row_start[col]` ---\n");
for (size_t row = 0; row < num_rows; row++)
{
const int *row_start = array_2d[row]; // VERY DIFFERENT FROM `print_array4` above!
for (size_t col = 0; col < num_cols; col++)
{
// Identical to `print_array4` above.
printf("array_2d[%zu][%zu]=%i ", row, col, row_start[col]);
}
printf("\n");
}
printf("--- Technique 2: use `array_2d[row][col]` ---\n");
for (size_t row = 0; row < num_rows; row++)
{
for (size_t col = 0; col < num_cols; col++)
{
// OR you can simply do this!
printf("array_2d[%zu][%zu]=%i ", row, col, array_2d[row][col]);
}
printf("\n");
}
printf("\n");
}
// 2. Basic usage
print_array5(all_rows, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
// 3. Usage via a pointer
//
// 3.1. Easier way: ptr to "ptr to int"; note: `int* array_2d[]` naturally
// decays to `int**`.
const int **p5_1 = all_rows;
print_array5(p5_1, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
//
// 3.2. OR this more-complicated way, for the sake of demonstration:
// ptr to array of 3 `int*`s
const int* (*p5_2)[ARRAY_LEN(all_rows)] = &all_rows;
// Explanation: the type of `p5_2` is `int* (*)[3]` (ptr to array of 3
// int*), so the type of `*p5_2` is `int* [3]` (array of 3 int*), which
// decays naturally to `int**`, which is what `*p5_2` ends up passing to
// this function call! So, this call to `print_array5()` here and the one
// just above are therefore exactly identical!
print_array5(*p5_2, ARRAY_LEN(all_rows), ARRAY_LEN(row1));
不要忘记结构!
但不要忘记,有时,只使用结构会容易得多!
例子:
typedef struct data_s
{
int x;
int y;
} data_t;
// Array of the above struct
data_t data_array[] =
{
{1, 2},
{5, 6},
{7, 8},
};
void print_struct_data(data_t * data, size_t len)
{
for (size_t i = 0; i < len; i++)
{
printf("[data[%zu].x, data[%zu].y] = [%i, %i]\n",
i, i, data[i].x, data[i].y);
}
printf("\n");
}
print_struct_data(data_array, ARRAY_LEN(data_array));
输出:
[data[0].x, data[0].y] = [1, 2]
[data[1].x, data[1].y] = [5, 6]
[data[2].x, data[2].y] = [7, 8]
完整的、可运行的代码:
完整的、可运行的代码会导致此答案超过答案中允许的最大 30000 个字符。因此,请在此处下载完整代码:c/2d_array_practice.c,在我的 eRCaGuy_hello_world 存储库中。
示例输出(减少;请自行运行完整代码):
print_array1:
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
print_array2:
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
print_array3:
--- Technique 1: ---
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
--- Technique 2: ---
array_2d_ptr[0][0]=1 array_2d_ptr[0][1]=2
array_2d_ptr[1][0]=5 array_2d_ptr[1][1]=6
array_2d_ptr[2][0]=7 array_2d_ptr[2][1]=8
print_array4:
--- Technique 1: ---
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
--- Technique 2: ---
array_2d_ptr[0][0]=1 array_2d_ptr[0][1]=2
array_2d_ptr[1][0]=5 array_2d_ptr[1][1]=6
array_2d_ptr[2][0]=7 array_2d_ptr[2][1]=8
print_array5:
--- Technique 1: use `row_start[col]` ---
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
--- Technique 2: use `array_2d[row][col]` ---
array_2d[0][0]=1 array_2d[0][1]=2
array_2d[1][0]=5 array_2d[1][1]=6
array_2d[2][0]=7 array_2d[2][1]=8
Don't forget about just using structs and arrays of structs instead, which
is sometimes much easier!
[data[0].x, data[0].y] = [1, 2]
[data[1].x, data[1].y] = [5, 6]
[data[2].x, data[2].y] = [7, 8]
参考资料:
- 我使用的主要参考资料:我自己的答案,其中包含有关“在 C 中强制数组的类型安全”的信息,以及如何解释和读取指向数组的一维指针,如下所示:
int (*a)[2]:@ 987654331@
- https://www.geeksforgeeks.org/pass-2d-array-parameter-c/
相关:
- [我的回答]Arduino Stack Exchange: Initializing Array of structs
- [我的答案引用了这个答案]Passing a pointer to array to my function