为什么在C语言中不能直接将数组赋值给指针?

16

我有如下程序。但是,我不明白为什么我必须传递数组的地址。当它们都指向相同的地址时。这个地址是int数组的第一个元素的地址。

当我尝试这样做时,我会收到一个警告“从不兼容的指针类型赋值”:

ptr = var;

完整的源代码:

void print_values(int (*ptr)[5])
{
    size_t i = 0;
    for(i = 0; i < 5; i++) {
        printf("%d: [ %d ]\n", i, (*ptr)[i]);
    }
}

int main(void)
{
    /* declare a pointer to an array integers */
    int (*ptr)[5] = NULL;
    /* array of integers */
    int var[] = {1, 2, 3, 4, 5};
    /* assign the address of where the array is pointing to (first element) */
    ptr = &var;
    /* Both are pointing to the exact same address */
    printf("var  [ %p ]\n",(void*)var);
    printf("&var [ %p ]\n", (void*)&var);

    print_values(ptr);
    return 0;
}

我使用 gcc 4.4.4 c89 -Wall -Wextra -O0 编译代码


我试图重新措辞您的标题,因为它没有意义。请确认我是否正确地理解了您的问题要点。 - P Shved
我觉得你的标题比我的好听。谢谢。 - ant2009
你的代码片段编译正常。你的意思是如果在主函数中添加 ptr = var 会出现错误吗? - Ciro Santilli OurBigBook.com
4个回答

24

这只是一个类型问题。

在大多数表达式上下文中,数组的名称(例如var)会衰减为指向数组初始元素的指针,而不是指向数组本身的指针。[请注意,这并不意味着var是指针——它绝对不是指针——它只是在大多数表达式中表现得像指向数组第一个元素的指针。]

这意味着在表达式var中,它通常会衰减为指向int的指针,而不是指向int数组的指针。

作为地址运算符(&)的操作数是一个不适用这种衰减规则的上下文环境(另一个是sizeof运算符的操作数)。在这种情况下,&var的类型直接从var的类型推导出来,因此类型是指向包含5个int的数组的指针。

是的,指针具有相同的地址值(数组第一个元素的地址就是数组本身的地址),但它们具有不同的类型(int*int (*)[5]),因此在赋值中不兼容。

ISO/IEC 9899:1999 6.3.2.1/4:

 

除非它是sizeof操作符或一元&操作符的操作数,或者是用于初始化数组的字符串文字,否则具有类型“type的数组”表达式将转换为指向该数组对象的初始元素的类型为“type”的表达式,而不是lvalue。...


我曾认为只有在函数调用时,数组才会衰变为指针。所以在表达式 int arr[5] = {1,2,3,4,5}; int *ptr = arr; 中,当数组被分配给指针时,它会衰变为指针吗? - ant2009
@robUK:不仅仅是函数调用,大多数表达式上下文中都会发生衰减。当数组用于初始化指针时,它会发生衰减;需要指针值来初始化指向int的指针,而不是int数组。 - CB Bailey

6

var 是一个指向数组第一个元素的 (*int) 指针。在 C 语言中,指针和数组非常相似。将 int (*ptr)[5] = NULL; 改为 int* ptr = NULL;,并将 ptr = &var; 改为 ptr = var;


4
C语言是一种强类型语言。当一个函数需要一个int *类型的参数时,你必须传递一个int *类型的参数。不能是double *或者char *,而只能是int *。即使在那些double *或者char *中实际的数值地址与你想要传递的地址相同,也不会改变任何东西——你仍然必须传递一个int *。语言禁止你传递错误类型的值。
这正是你的情况所发生的事情。该函数需要一个int (*)[5]类型的参数。这意味着你必须传递该类型的参数。不能传递int *类型的参数。无论地址是否相同都没有任何区别。

1
从我的理解来看,您正在将一个数组指针(var)分配给指向数组指针的指针((*ptr)[5]),这就是为什么会出现警告的原因。
相反地,请尝试使用
int *ptr = NULL;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接