引用数组与数组指针的引用

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; 

第一个工作,但第二个不工作。 我不明白为什么会这样。

C规范说数组和&数组是相同的指针地址。

将数组传递给函数时使用数组的名称会自动将参数转换为符合C规范的指针(强调我的)。

6.3.2.1-4

除非它是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为”array of type”的表达式转换为类型为”指针的表达式type”指向数组对象的初始元素,而不是左值。 如果数组对象具有寄存器存储类,则行为未定义。

因此,调用func(array)将导致将char []的指针传递给函数。 但是在arrays上使用address-of运算符有一种特殊情况。 由于数组的类型为“数组类型”,因此它属于规范的“其他”类别(强调我的)。

6.5.3.2-3

一元&运算符产生其操作数的地址。 如果操作数具有类型”type”,则结果具有类型”指向类型”的指针。 如果操作数是一元*运算符的结果,则不会对该运算符和&运算符进行求值,结果就好像两者都被省略,除了对运算符的约束仍然适用且结果不是左值。 类似地,如果操作数是[]运算符的结果,则[]运算符和[]隐含的一元*都不会被计算,结果就像删除了&运算符并且[]运算符被更改为a +运算符。 否则,结果是指向由其操作数指定的对象或函数的指针

因此,调用func(&array)仍会导致单个指针传递给函数,就像调用func(array)一样,因为数组和&数组都是相同的指针值。

常识会让你相信&array是指向数组第一个元素的双指针,因为使用&运算符通常就是这样。 但arrays是不同的。 因此,当您将传递的数组指针作为指向数组的双指针取消引用时,会出现Segmentation错误。

问题是,当我们执行&array ,我们从char [10]获取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); 

blachar * ,而&blachar **

但是, arraychar [10] ,而&arraychar (*)[10]而不是char **

因此,当您将&array作为参数传递时, char (*)[10]在作为参数传递时就像char * ,如上所述。

因此**(char **) &bla == 'j'*(char *) &array == 'j' 。 做一些简单的实验,你会certificate它。

而且你正在将void *elemAddr转换为char **并尝试将其推荐出来。 这只适用于&bla因为它是char **&array将导致段错误,因为“john”在执行转换时被解释为地址。

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);代码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);代码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; } 

这不是您问题的直接答案,但将来可能对您有所帮助。

数组不是指针:


  • type arr[10]

    • 使用sizeof(type)*10字节的量

    • arr&arr的值必须相同

    • arr指向有效的内存地址,但不能设置为指向另一个内存地址


  • type* ptr = arr

    • 使用额外量的sizeof(type*)字节

    • 除非设置ptr = (type*)&ptr ,否则ptr&ptr的值通常是不同的

    • ptr可以设置为指向有效和无效的内存地址,可以多次使用


至于你的问题: &bla != bla == array == &array ,因此&bla != &array

一个问题是你的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变量的地址 ,并且与其值(或它指向的内容)无关。

希望有所帮助。