我遇到过类似以下的C代码:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(200*sizeof(int));
int i;
for (i = 0; i < 200; i++)
{
a[i] = i;
}
int (*b)[10] = (void*) a;
printf("\nsizeof(int):\t%d\n", sizeof(int));
printf("\nb[0]:\t%d\n", b[0]);
printf("\na:\t%d\n", a);
printf("\nb[19]:\t%d\n", b[19]);
printf("\na+190:\t%d\n", a+190);
printf("\nb[0][8]:\t%d\n", b[0][8]);
printf("\nb[19][9]:\t%d\n", b[19][9]);
return 0;
}
根据我的理解,行int (*b)[10] = (void*) a;
正在尝试将指针b
(应该指向10个整数的数组)分配给数组a
类型转换的起始地址作为一个无效指针。我希望b[i]
为a[i]
保留与i=0..9
相同的数据(以及b
的0到9之外的任何索引,导致一些未定义的行为)。但是,该程序产生的输出类似于以下样本:
sizeof(int): 4
b[0]: 9768976
a: 9768976
b[19]: 9769736
a+190: 9769736
b[0][8]: 8
b[19][9]: 199
显然,b
已成为一个包含20个指针的数组,每个元素指针指向a
数组的唯一部分,每个部分对应10个整数(或40个字节)。有人可以解释一下int (*b)[10] = (void*) a;
究竟是什么吗?具体来说,类型转换(void *)
如何帮助在a
的多个元素之间分发整个b
?如果没有(void *)
强制转换,上述代码将无法编译。
答案 0 :(得分:0)
这样看:
int *a;
a = malloc(200 * sizeof(int));
int (*b)[10];
b = (void *)a;
因此,第一行表示a
应指向int
。第二行分配一个可容纳200 int
s的内存块,并将此块的起始地址分配给a
。第三行表示b
应该指向一个10 int
的数组。第四行表示b
应分配a
所持的地址。
所以现在b
指向从int
调用返回的地址开始的10 malloc()
个数组。由于内存分配给200 int
s,b
指向一个内存块,可以容纳20个10个元素的int
数组。
需要转换为void
,因为a
被声明为int
的指针;这允许您将a
中的值保存在b
中,即使它们属于不同类型。我认为这只是为数组分配适当内存量的方便。另一种避免完全声明a
的方法是:
int (*b)[10] = malloc(20 * sizeof(*b));
根据读者的口味,这第二种方法可能会或可能不会更加神秘。我想第一种方法的一个优点是,它允许您按顺序和作为二维数组访问数组的元素。
答案 1 :(得分:0)
显然,
b
已成为一个包含20个指针的数组,每个元素指针指向a
数组的唯一部分,每个部分对应10个整数(或40个字节)。
不,b
只是一个指针,而不是一个数组。类型b
指向的数组为10 - int
s。如果您将其视为:
typedef int row[10]; // A `row` is an array of 10 ints
row* b = (void*) a;
对于任何指针T* p
,p[n]
是sizeof (T)
个字节偏离p[n - 1]
(假设n
和n - 1
是有效索引,课程)。这个案子没有什么不同;此处T
是一个10个元素的int
数组,因此b
的每个元素都距离其相邻元素10 * sizeof (int)
个字节。
具体来说,类型转换
(void *)
如何帮助在a
的多个元素之间分发整个b
?如果没有(void *)
强制转换,上述代码将无法编译。
在C中,指针可以在void*
和T*
之间转换而无需显式转换。上面的案例使用void*
强制转换来减少输入;它允许将右侧转换为左侧所需的任何指针类型。