现有的答案虽然正确,但并没有很清楚地表明为什么你无法将
char [10][10]
强制转换为
char **
,除了编程语言规则之外还有一个根本原因。即使你用类似于强制转换的方式来进行转换:
char arr[2][2];
char ** ptr = (char **)arr;
它实际上不起作用。
原因是在C和C++中,二维数组在内存中是以数组的形式排列的。也就是说,在C中,二维数组在内存中是作为单个分配排列的。
arr -> arr[0][0]
arr[0][1]
arr[1][0]
arr[1][1]
您会注意到,arr
指向的不是一个 char *
,而是指向 arr[0][0]
,它是一个 char
;因此,虽然可以将 arr
强制转换为 char *
,但不能将其强制转换为 char **
。
正确的强制转换应该是
char arr[2][2];
char * ptr = (char *)arr;
如果可能的话,您不想强制转换(这总是一个好主意!)
char arr[2][2];
char * ptr = arr[0];
或者,为了使结果更加清晰明了,
char arr[2][2];
char * ptr = &arr[0][0];
现在您实际上拥有一个指向包含4个字符的数组的指针。[注:我没有找到C标准中禁止实现在数组的两行之间添加填充的任何内容,但我不认为任何真实世界的实现会这样做,并且常见的编码实践依赖于这种假设不存在这样的填充。]
如果您确实需要将arr
转换为char **
,您必须显式创建指针数组:
char arr[2][2]
char * arr_ptrs[2];
char ** ptr;
arr_ptrs[0] = arr[0];
arr_ptrs[1] = arr[1];
ptr = arr_ptrs;
如果您尝试将二维数组强制转换为指向指针的指针,C语言原则上可以自动完成此操作,但这将违反程序员的期望,即强制转换不会具有诸如分配内存之类的副作用。
相比之下,在Java中,二维数组始终是指向数组的指针数组,因此该数组
char arr[][] = { {'a', 'b'}, {'c', 'd'} };
在内存中,它被分为三个单独的分配,以任意顺序和不一定相邻的方式进行布置。
arr -> arr[0]
arr[1]
arr[0] -> arr[0][0]
arr[0][1]
arr[1] -> arr[1][0]
arr[1][1]
你会立即注意到,这需要比相当的C数组更多的内存,并且在运行时评估速度较慢。另一方面,它确实允许数组的行具有不同的长度。