繁体   English   中英

将数组的指针传递给C中的函数

[英]Passing pointer of an array to a function in C

所以我想问以下关于我朋友问我的一些代码的问题

在大多数情况下,如果我发现自己使用数组,我只允许自己发送数组的名称,因为它会衰减到指针,例如:

#include <stdio.h>

void foo(int *arr_p)
{
    arr_p[0] = 111;
    arr_p[1] = 222;
    arr_p[2] = 333;
}

int main()
{
    int arr[] = {1,2,3};
    foo(arr);
    printf("%d %d %d",  arr[0], arr[1], arr[2]);
}

正如预期的那样,这将打印 111、222、333

然而,我有一个朋友问我,如果出于某种原因我想传递一个指向该数组指针的指针会发生什么。

#include <stdio.h>

void foo(int **arr_p)
{
    *arr_p[0] = 111;
    *arr_p[1] = 222;
    *arr_p[2] = 333;
}

int main()
{
    int arr[] = {1,2,3};
    foo(&arr);
    printf("%d %d %d",  arr[0], arr[1], arr[2]);
}

现在这是他发给我的代码......它有一个分段错误,老实说我真的不知道为什么。 我想取消引用数组的指针会给我留下一个指向数组的指针,不是吗?

虽然普通数组名称确实会衰减为指针,但指向数组的指针不会衰减为指向指针的指针。 数组到指针的转换来自这样一个事实,即数组的地址与其第一个元素的地址相同,之后其他元素在内存中跟随。 指向数组的指针不能用作指向其元素类型的指针的指针:在数组的地址中驻留的是数组的元素(在您的示例中为int类型),而不是指针。

要在函数中接收指向数组的参数,您必须明确声明它如下:

void foo(int (*arr_p)[])
{
    (*arr_p)[0] = 111;
    (*arr_p)[1] = 222;
    (*arr_p)[2] = 333;
}

注意添加的括号; 这是因为索引运算符[]在 C 中比解引用运算符*具有更高的优先级; 所以*arr_p[i]将首先索引一个指针数组,然后取消引用获得的指针(同样int *arr_p[]将声明一个指针数组参数)。

关于您的段错误的更多见解。 只需查看编译的 assebly 即可了解 GodBolt 上int**int(*)[]的区别

编译行时(*arr_p)[0] = 111; 使用int**你会得到:

mov     rax, QWORD PTR [rbp-8]
mov     rax, QWORD PTR [rax]
mov     DWORD PTR [rax], 111

而使用int(*)[]你得到

mov     rax, QWORD PTR [rbp-8]
mov     DWORD PTR [rax], 111

您看到(并理解)其中的区别了吗? 使用int**它应用双重解除引用,因为您告诉编译器您正在将指向指针的指针作为参数传递。 int(*)[]的情况下,编译器理解它是一个指向数组的指针,并正确地取消引用一次。

在 C++ 中,由于这个问题,这段代码甚至无法编译。 实际上,为了类型安全甚至不允许int(*arr)[] :它应该是int(*arr)[3]

发生这种情况是因为换句话说,您将 arr 声明为:

int arr[3];
arr[0]=1;arr[1]=2;arr[2]=3;
foo(&arr);

然后,当您将地址传递给 foo 时,它实际上是一个指向 3 数组的指针。

void foo(int (*arr_p)[3])
{
    *arr_p[0] = 111;
    *arr_p[1] = 222;
    *arr_p[2] = 333;
}

然后 arr_p[0] 是第一个 3 数组,arr_p[1] 是第二个 3 数组,而 arr_p[2] 是第三个。

因此,当您写入 *arr_p[1] = 222 时,您正在分配的内存之外写入您传递给 foo 的内容,并且您具有未定义的行为。

它们不是 one 数组中的单个索引

这会起作用,但没有任何意义:

void foo(int (*arr_p)[3])
{
    *arr_p[0] = 111;
    *arr_p[1] = 222;
    *arr_p[2] = 333;
}

int main()
{
    int arr[3][3];
    foo(arr);

    printf("%d %d %d",  arr[0][0], arr[1][0], arr[2][0]);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM