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

时间:2015-01-03 13:36:02

标签: c arrays pointers

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;

第一个有效,但第二个无效。我不明白为什么会这样。

5 个答案:

答案 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);

blachar *&blachar **

但是,arraychar [10]&arraychar (*)[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

    • ,否则&ptrptr = (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变量的地址并且与其值无关(或者它指向的是什么。)

希望有所帮助。