指向连续二维数组内存位置问题的双指针

Double pointer to a contiguous 2D array memory location issue

我有以下 C 语言代码,无法弄清楚为什么会抛出异常(内存访问冲突)。 根据我对使用双指针的理解,我应该能够通过索引访问数组,因为它是连续的。 我的最终目标是仅通过指针将一些值存储在 array_double 中。

uint8_t array_double[4][15];
uint8_t *single_ptr = array_double;
uint8_t **double_ptr = &single_ptr;
uint8_t value;

value = double_ptr[0][14]; // this works
value = double_ptr[1][0]; // throws an exception

double_ptr[0][14] = write_value; // this works
double_ptr[1][0] = write_value; // throws an exception

double_ptr 指向单个对象:变量 single_ptr。使用指针算法 double_ptr[1],您超出了该单个对象的范围。访问该内存会导致未定义的行为。

此外:

uint8_t *single_ptr = array_double;

变量的类型与初始化程序不匹配。程序格式错误


如果你真的想使用指向二维数组的指针,那么你需要有一个指针数组:

uint8_t *ptrs[4];
for(size_t i = 0; i < 4; i++) {
    ptrs[i] = array_double[i];
}
uint8_t **double_ptr = ptrs;
value = double_ptr[1][0]; // OK

您可以使用指向数组的指针来代替指向指针的指针:

typedef uint8_t Array[15];
Array* array_pointer = array_double;
value = array_pointer[1][0]; // OK

或者您可以编写这样的函数:

void foo(size_t x, size_t y, uint8_t array_double[x][y])
{
    assert(x > 1 && y > 0);
    uint8_t value = array_double[1][0]; // OK
    // ...
}

int main()
{
    uint8_t array_double[4][15];
    foo(4, 15, array_double);
}

P.S。我建议不要将指向指针的指针称为“双指针”,因为在上下文之外可以假定它意味着 double*

.

启用所有警告以节省时间。

uint8_t *single_ptr = array_double; 是错误的代码,因为它使用错误的类型进行初始化。


定义指向数组第一个元素的正确类型的指针 array_double[]
uint8_t (*single_ptr)[C] 是一个 pointer to array C of uint8_t

// Reading example
#define R 2
#define C 3
int main(void) {
  uint8_t array_double[R][C] = {{1,2,3},{4,5,6}};
  uint8_t (*single_ptr)[C] = array_double;
  printf("%d\n", single_ptr[0][1]);
  printf("%d\n", single_ptr[1][0]);
}

输出

2
4

这些指针声明

uint8_t array_double[4][15];
uint8_t *single_ptr = array_double;
uint8_t **double_ptr = &single_ptr;

不正确。

对于符合 C 标准的初学者(6.3.2.1 左值、数组和函数指示符)

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

这个数组的元素类型

uint8_t array_double[4][15];

uint8_t[15]。因此,指向数组初始元素的指针的类型为 uint8_t( * )[15].

因此,使用数组 array_double 作为初始值设定项的 single_ptr 的有效声明将类似于

uint8_t ( *single_ptr )[15] = array_double;

指向 single_ptr 的指针看起来像

uint8_t ( **double_ptr )[15] = &single_ptr;

使用指针 single_ptr 你可以写

value = single_ptr[0][14];

使用指针 double_ptr 你可以写

value = ( *double_ptr )[1][0];

要使用 single_ptr 设置数组元素,您可以编写

single_ptr[0][14] = write_value;

要使用 double_ptr 设置数组元素,您可以编写

( *double_ptr )[1][0] = write_value;

为了更清楚,让我们考虑以下赋值语句

value = single_ptr[0][14];

表达式 single_ptr[0] 生成数组 array_double 的第一个元素,它表示 uint8_t[15] 类型的一维数组 - 数组 [=23= 的第一个元素].下标表达式 single_ptr[0][4] 中使用的表达式 single_ptr[0] 指定的一维数组依次隐式转换为一维数组的第一个元素,应用下标运算符。您可以通过以下方式引入中间变量

// single_ptr[0] has the type uint8_t[15]
// and used as an expression in the statement below
// is implicitly converted to pointer to the element type 
// that is to a pointer of the type uint8_t *`
uint8_t *row = signle_ptr[0]; 
value = row[14];