我有以下代码。调用 f1 会引发段错误,但调用 f2 不会。
#include <stdlib.h>
#include <stdio.h>
void f1(unsigned char** arr)
{
unsigned char* p = *arr;
*p = 'h';
p++;
*p = '\0';
}
void f2(unsigned char* arr)
{
unsigned char* p = arr;
*p = 'h';
p++;
*p = '\0';
}
int main()
{
unsigned char a[31];
f1((unsigned char**)&a);
//f2(a);
printf("%s\n", a);
}
unsigned char**
是指向 的指针的指针unsigned char
。&a
返回数组的地址a[]
。返回的类型&a
是unsigned char (*)[31]
,而不是unsigned char**
,这就是为什么你不能简单地调用,f1(a)
这是类型不匹配。注意那个错误,它很重要。&a
不返回指针的地址,但您使用类型转换来欺骗编译器认为它确实返回了,因此您强制f1()
通过无效指针访问无效的内存地址,从而导致段错误。换句话说,您正在使用一个指向数组的指针并将其强制转换为指向指针的指针,但事实并非如此。在内部
f1()
,*arr
取消引用期望产生unsigned char*
指向有效 的指针unsigned char
,但事实并非如此。arr
指向a[]
自身,因此读取*arr
将读取并误解前 4 个字节(在 32 位版本中)或 8 个字节(在 64 位版本中)为a[]
指针的值,但事实并非如此。然后取消引用该指针失败。不要盲目使用类型转换来消除编译器错误。它们之所以是错误,是有原因的。类型转换在某些情况下很有用,但这不是其中之一。在您的示例中,调用with 的正确方法如下:
f1()
a[]
或者,改为
f1()
接受指向数组的指针而不是指向指针的指针:至于为什么调用
f2(a)
按原样工作,那是因为数组退化为指向其第一个元素的指针,并且f2()
正确使用了该指针。调用时情况并非如此f1(&a)
。