我在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
我如何能够仅使用指针存储值(在)
array_double
。
启用所有警告以节省时间。
uint8_t *single_ptr = array_double;
是错误的代码,因为它初始化的类型错误。
定义一个指向数组array_double[]
的第一个元素的指针,uint8_t (*single_ptr)[C]
是指向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("%dn", single_ptr[0][1]);
printf("%dn", 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除非它是sizeof操作符的操作数或一元&操作符,或者是用于初始化数组的字符串字面值,和类型为"类型的数组"的表达式被转换为类型为"指向类型的指针"的表达式数组对象的元素并且不是左值。如果数组对象具有注册存储类,行为未定义。
数组元素的类型
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]
的一维数组——数组array_double
的第一个元素。下标表达式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];
double_ptr
指向单个对象:变量single_ptr
。使用指针算术double_ptr[1]
,您将超出该单个对象的边界。访问内存会导致未定义的行为。
此外:
uint8_t *single_ptr = array_double;
变量的类型与初始化器不匹配。程序格式错误
如果你真的想在2D数组中使用指针指向指针,那么你需要有一个指针数组:
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);
}
注:我不建议将指针的指针称为"双指针"。因为断章取义时,可以假定为double*
。