【问题标题】:Why don't I have to give the function the address of the array为什么我不必给函数数组的地址
【发布时间】:2015-02-21 02:37:06
【问题描述】:

您好,我是 C 新手,正在学习指针。我正在编写一个简单的递归函数来测试它的参数int *aint size。在我的主要方法中,我预先使用& 发送print_array 我数组的第一个字符的地址。

这似乎不起作用,我在编译时收到“不兼容的指针类型”错误。我知道我可以删除 & 并且程序运行良好。我有一个问题:

为什么我不能用 & 从 main 中传入 my_array 的内存地址?我不应该只给函数数组的第一个元素的内存地址,它就可以处理其余的吗?

谢谢,希望这个问题不是太菜鸟。

 #include <stdio.h>
 #include <stdlib.h>


void print_array(int *a, int size){
    if (size>0){
            printf("%d\n", a[0]);
            print_array(a+1, size-1);
    }
}

int main(void){
    int my_array[20];
    int i;

    for (i=0; i < 20; i++){
            my_array[i] = rand() % 20;
    }

    /*the contents of the array*/
    printf("The contents of the array\n");
    for (i=0; i < 20; i++){
            printf("%d\n", my_array[i]);
    }

    printf("The recursive method print\n");

    print_array(&my_array, 20);

    return EXIT_SUCCESS;

}

【问题讨论】:

    标签: c++ c arrays pointers


    【解决方案1】:

    是的,你可以给函数第一个元素的地址,让它处理剩下的。你可以这样做:

    print_array(my_array, 20);
    

    ...或:

    print_array(&my_array[0], 20);
    

    不幸的是,虽然&amp;my_array 是合法代码,但它会生成指向整个数组的指针,而不是指向数组第一个元素的指针。它们具有相同的地址,但类型不同,这就是导致错误的原因。

    指针的类型决定了(除其他外)该指针上的算术将如何工作。在您的情况下,print_array 打印数组中的第一个 int,然后将一个添加到指针中。由于它是一个指向 int 的指针,因此该添加实际上将 int 的大小添加到指针中的地址。

    如果您使用指向整个数组的指针,那么添加一个会将整个数组的大小添加到地址中。例如,假设 4 字节 int 并且 my_array 的基地址为 1000。在这种情况下,my_array+1 将产生 1004,因此它保存数组中第二个 int 的地址(正如您无疑想要的那样)。相比之下,&amp;my_array 将获取整个数组的地址,类型为“指向 20 个整数的数组的指针”。当您向其中添加 1 时,会将 1 * 指向类型的大小添加到地址中,因此您将获得 1080(即,整个数组为 20 * 4 = 80 字节)。这显然 不是 你想要的——而不是 x+1 指向第二个项目 in 数组,它现在指向数组的末尾,并试图取消引用指针将给出未定义的行为。

    所以,只需切换到上述形式之一(my_array&amp;my_array[0])。作为更一般的一点,请意识到在大多数情况下,数组的名称计算为指向数组第一个元素的指针——值得注意的例外是当您使用数组的名称作为 @987654331 的操作数时@ 运算符或地址运算符(就像您在此处所做的那样)。在这两种情况下,数组的名称仍然是指整个数组,而不是指向第一个元素的指针。

    【讨论】:

    • 如果print_array 的第一个参数被声明为int (*a)[20],那么您可以将&amp;my_array 传递给它。但是int *a 是指向整数的指针,而不是指向 20 个整数的数组的指针。这就是为什么您必须传递数组第一个元素的地址,而不是数组本身的地址(即使它们具有相同的数值)。
    • @Wyzard:是的,如果参数被声明为int (*a)[20],你可以传递&amp;my_array,但是print_array内部的a+1会产生未定义的行为。
    • "不幸的是,虽然 &my_array 是合法代码,但它会生成指向整个数组的指针,而不是指向数组第一个元素的指针。它们的地址相同,但类型不同,即是什么导致了错误。”你能详细说明一下吗?那么&amp;my_array 会给我一个指向整个数组的指针吗?它们将如何是不同类型的它们都指向同一个块?谢谢
    • @magna_nz:我已经添加了更多细节。
    【解决方案2】:

    您的函数需要一个指向 int 的指针,特别是数组的第一个(第 0 个)元素的地址。

    通过调用print_array(&amp;my_array, 20);,您试图传递整个数组的地址,一个int(*)[20] 类型的值,它与int* 不同。它指向同一个内存位置,但类型不同。

    要传递第一个元素的地址,可以这样写:

    print_array(&my_array[0], 20);
    

    或者,等效地:

    print_array(my_array, 20);
    

    后者之所以有效,是因为在大多数但不是所有情况下,数组的名称都会隐式转换为指向其第一个元素的指针。

    C 和 C++ 中的数组和指针之间的关系可能令人困惑。推荐阅读:comp.lang.c FAQ第6节

    【讨论】:

      【解决方案3】:

      因为数组会自动衰减为指针,所以下面摘自n1570草稿

      6.3.2 其他操作数

      6.3.2.1 左值、数组和函数指示符

      1. 除非它是sizeof 运算符、_Alignof 运算符或 一元 &amp; 运算符,或者是用于初始化数组的字符串文字,该表达式具有 type ‘‘array of type’’ 被转换为类型为 ‘‘pointer to type’’ 的表达式,它指向 到数组对象的初始元素并且不是左值。如果数组对象有 注册存储类,行为未定义。

      【讨论】:

      • 请注意,关于 _Alignof 运算符的措辞不正确,已从最终的 C11 标准中删除。与sizeof 不同,_Alignof 只能应用于类型,不能应用于表达式。 (目前尚不清楚为什么会这样。)
      • @KeithThompson 感谢您的评论,我不拥有C11 标准。只是草稿。
      猜你喜欢
      • 1970-01-01
      • 2020-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-11
      • 2020-09-10
      • 2021-06-02
      相关资源
      最近更新 更多