void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main(){
char array[10] = {'j','o','h','n'};
char * bla = array;
check(&bla);
check(&array);
}
输出:
word is john
RUN FINISHED; Segmentation fault; core dumped;
第一个有效,但第二个无效。我不明白为什么会这样。
答案 0 :(得分:7)
问题是,当我们&array
时,我们从char (*)[10]
而不是char [10]
获得char **
。
在我们进行实验之前,我要强调的是,当我们将数组作为参数传递给函数时,C实际上将数组转换为指针。不会复制大量数据。
因此,int main(int argc, char **argv)
与C中的int main(int argc, char *argv[])
相同。
这使我们可以使用简单的printf
打印数组的地址。
我们来做实验:
char array[] = "john";
printf("array: %p\n", array);
printf("&array: %p\n", &array);
// Output:
array: 0x7fff924eaae0
&array: 0x7fff924eaae0
知道了这一点后,让我们深入研究你的代码:
char array[10] = "john";
char *bla = array;
check(&bla);
check(&array);
bla
为char *
,&bla
为char **
。
但是,array
为char [10]
,&array
为char (*)[10]
而不是char **
。
因此,当您将&array
作为参数传递时,char (*)[10]
在作为参数传递时就像char *
一样,如上所述。
因此**(char **) &bla == 'j'
*(char *) &array == 'j'
。做一些简单的实验,你就会证明它。
您正在向void *elemAddr
投射char **
并尝试尊重它。这仅适用于&bla
,因为它是char **
。 &array
会导致段错误,因为“john”会在您执行转换时被解释为地址。
答案 1 :(得分:3)
对于check(&bla);
您要发送pointer to pointer
void check(void* elemAddr){
char* word = *((char**)elemAddr); // works fine for pointer to pointer
printf("word is %s\n",word);
}
这很好用。
但是,对于check(&array);
,您只传递指针
void check(void* elemAddr){
char* word = *((char**)elemAddr); // This is not working for pointer
char* word = *(char (*)[10])(elemAddr); // Try this for [check(&array);]
printf("word is %s\n",word);
}
完整代码 -
check(array);
的代码:
void check(void* elemAddr){
char* word = *(char (*)[10])(elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
check((char*)array);
return 0;
}
check(&bla);
的代码:
void check(void* elemAddr){
char* word = *((char**)elemAddr);
printf("word is %s\n",word);
}
int main() {
char array[10] = {'j','o','h','n'};
char* bla = array;
check(&bla);
return 0;
}
答案 2 :(得分:1)
这不是您问题的直接答案,但将来可能对您有所帮助。
数组不是指针:
type arr[10]
:
使用sizeof(type)*10
个字节
arr
和&arr
的值必须相同
arr
指向有效的内存地址,但不能设置为指向另一个内存地址
type* ptr = arr
:
使用额外数量的sizeof(type*)
字节
除非您设置ptr
&ptr
和ptr = (type*)&ptr
的值通常会有所不同
ptr
可以设置为指向有效和无效的内存地址,可以多次使用
关于您的问题:&bla != bla == array == &array
,因此&bla != &array
。
答案 3 :(得分:1)
C规范说数组和&数组是相同的指针地址。
将数组传递给函数时使用数组的名称会自动将参数转换为符合C规范的指针(强调我的)。
6.3.2.1-4
除非它是sizeof运算符或一元&的操作数。 operator,或者是用于初始化数组的字符串文字, an 具有类型''数组类型''的表达式将转换为 带有''指向类型'的指针的表达式,指向初始值 数组对象的元素并且不是左值。如果是数组对象 具有寄存器存储类,行为未定义。
因此调用func(array)会导致将char []的指针传递给函数。但是在阵列上使用address-of运算符有一种特殊情况。由于数组的类型为“数组类型”,因此它属于规范的“其他”类别(强调我的)。
6.5.3.2-3
一元&运算符产生其操作数的地址。如果是操作数 类型为''type'',结果有''指向类型''的指针。如果 操作数是一元*运算符的结果,既不是运算符也不是运算符 和&运算符被评估,结果就像两个都被省略, 除了对运营商的约束仍然适用和 结果不是左值。同样,如果操作数是a的结果 []运营商,既不是&操作员或暗示的一元* 对[]进行评估,结果就像&经营者 删除并将[]运算符更改为+运算符。的否则, 结果是指向由其指定的对象或函数的指针 操作数强>
因此,调用func(& array)仍会导致单个指针传递给函数,就像调用func(array)一样,因为数组和&数组都是相同的指针值。
常识会让你相信&数组是指向数组第一个元素的双指针,因为使用&运营商通常表现得那样。但阵列是不同的。因此,当您将传递的数组指针作为指向数组的双指针取消引用时,会出现Segmentation错误。
答案 4 :(得分:-1)
一个问题是你的char数组不是NECESSARILY将被空终止。由于 array
是在堆栈上本地分配的自动变量,因此不能保证将其置于清零状态。因此,即使您正在初始化前4个字符,后6个字符也未定义。
然而......
你的问题的简单答案是&bla != &array
所以你的check()函数假设它会在2个不同的地址找到空终止的字符数组。
以下等式是正确的:
array == &array // while not the same types exactly, these are equivalent pointers
array == bla
&array == bla
*bla == array[0]
&bla
永远不会等于你想要的任何东西,因为该语法引用了本地堆栈上bla
变量的地址并且与其值无关(或者它指向的是什么。)
希望有所帮助。