【问题标题】:Passing 1D array, 2D arrays and pointer Arrays传递一维数组、二维数组和指针数组
【发布时间】:2018-07-04 08:15:20
【问题描述】:

要将一维数组传递给函数,我们这样做:

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

void func(int *arr, int n)
{
    // code here

}

int main()
{
    int arr[] = {......};                   // declare array
    int n = sizeof(arr)/sizeof(arr[0]);
    func(arr);                              // calling function func

    return 0;
}

要将二维数组传递给函数,我们这样做:

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

void func(int arr[][2])
{
    // code here
    }

int main()
{
    int arr[3][2];  // declare 2D array
    func(arr);      // calling function func

    return 0;
}

那么在将指针数组传递给函数时,我们可以这样做吗?

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

void func(int **arr, int n)
{
    // code here

}

int main()
{
    int *arr[] = {......};                // declare array of pointers
    int n = sizeof(arr)/sizeof(arr[0]);
    func(arr, n);                           // calling function func

    return 0;
}

老实说,我对指针和数组感到困惑。我花了很长时间才弄清楚如何传递二维数组。我尝试搜索其他类似的问题,但无济于事。请帮助我:将指针数组传递给函数。此外,任何我可以消除混淆的链接将不胜感激。

【问题讨论】:

  • 可以,int ** val,逻辑上等价于int val[n][m];它们不一样,但可以这样对待。但是应该注意,您检索两个 D 数组的所述大小的方法在本质上似乎有点狡猾,因为看起来您只能找到其中一个维度的大小,并设置两个维度之一。
  • 这里唯一的问题是你不能直接在堆上分配int *

标签: c arrays pointers


【解决方案1】:

老实说,我对指针和数组感到困惑。我花了很长时间才弄清楚如何传递一个二维数组。

这种混淆非常普遍。这是因为您在 C 中不能传递数组,但该语言允许使用一种语法,使其看起来像可以传递。

因此,由于您不能将数组传递给函数,因此您要做的是将指向第一个数组元素的指针传递给它,如果需要,还传递数组的大小。在函数内部,您可以使用该指针访问数组,语法看起来与实际数组相同。这也需要解释一下:

  • 索引运算符[] 通过将索引添加到给定指针并取消引用结果指针来工作。所以写a[5]*(a+5)完全一样。
  • 如果a 是一个实际的数组(而不是指针),这甚至可以工作,因为数组的计算结果是指向第一个元素的指针在大多数情况下(有像@987654325 这样的例外@ 运算符)。

为了让事情变得更复杂,C 允许声明看起来像是在使用数组的函数,例如你可以写:

void foo(int bar[]);

C 标准中有一条规则说函数参数类型需要“类型调整”:数组类型的任何参数都会自动调整为相应的指针类型。所以,上面的功能其实是一样的

void foo(int *bar);

因此,最好忘记传递数组(我什至建议不要在函数参数中使用数组语法,但这有待商榷)——你总是传递指针。


有了这些知识,您可以轻松地为所有案例构建正确的示例:

(1)“普通”数组

void foo(int bar[], size_t n); // with type adjustment
void foo(int *bar, size_t n);  // what it really means

// call like
int a[5];
foo(a, 5);

(2)二维数组

二维数组是数组的数组,所以它的第一个元素本身就是一个数组 -> 你可以传递一个指向数组的指针

void foo(int bar[][10], int n);  // with type adjustment, 2d array of n x 10
void foo(int (*bar)[10], int n); // what it really means

// call like:
int a[5][10];
foo(a, 5);

(3) 指针数组

指针数组通常用作二维数组的替代品——因为元素只是指针,它们可以指向单个值或不同长度的数组,但缺点是你没有完整的数据作为内存中的单个块,就像真正的二维数组一样。由于这只是一个指针数组,它看起来非常像一个“普通”的数组:

void foo(int *bar[], int n); // with type adjustment
void foo(int **bar, int n);  // what it really means

// call like:
int *a[5];
foo(a, 5);

最后一点:您经常会在 C 中读到数组“衰减为指针”。这不是官方措辞,但非常普遍。如果您将在大多数情况下(例如,将其传递给函数时)数组标识符计算为指针的规则与函数参数的类型调整规则相结合,结果是您编写数组语法到处都是,但得到指针,所以这就是“腐烂”的意思。

【讨论】:

  • 我相信定义像'void foo(int bar[10])'这样的函数的优点是调试器知道元素的数量并可以在变量窗口中显示它们。如果只传递一个指针,调试器只显示第一个元素。
【解决方案2】:

在上一个示例中,您有一个指针数组

是的,这会起作用,例如这个玩具示例:

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

void func(int **arr, int n) {

    // print equal to arr[0][1] 
    printf("%d %d\n", n, *arr[1]);
}

int main(void) {
    int a = 1, b = 2, c = 3;

    // set the points of a, b, and c, to arr[0][0..2];
    int *arr[] = {&a, &b, &c};
    int n = sizeof(arr)/sizeof(arr[0]);
    printf("%d %d\n", n, *arr[1]);

    func(arr, n);

    return 0;
}

输出:

3 2
3 2

【讨论】:

    【解决方案3】:

    实际上一维数组、二维数组、X-D 数组和指针数组之间没有区别。它们都只是随之而来的内存区域。

    一维数组:

    int arr[8];
    int *addr = arr;
    
    | arr[0] | ...*6... | arr[7] |
    ^                   ^
    |                   |
    addr                 addr+7
    

    二维数组:

    int arr[4][2]
    int *addr = arr[0];
    
    | arr[0][0] | ...*6... | arr[3][1] |
    ^                      ^
    |                      |
    addr                   addr+7 
    

    3-D 数组:

    int arr[2][2][2];
    int *addr = arr[0][0];
    
    | arr[0][0][0] | ...*6... | arr[1][1][1] |
    ^                         ^
    |                         |
    addr                      addr+7
    

    指针数组:

    typedef pointer int*;
    ...
    
    int a0[8] = {0, 1, 2, 3, 4, 5, 6, 7};
    int a1[7] = {0, 1, 2, 3, 4, 5, 6};
    ...
    int a7[1] = {0};
    
    pointer arr[8] = {a0, a1, a2, a3, a4, a5, a6, a7};
    pointer *addr = arr;
    
    | arr[0] = a1 | ...*6... | arr[7] = a7 |
    ^                        ^
    |                        |
    addr                     addr+7
    

    定义一个X-D数组可以如下实现:

    typedef data_type int;
    
    typedef struct X-Array
    {
        int d1;
        int d2;
        ...
        int dx;
        data_type *data;
    } X-Array;
    
    X-Array *create_X_Array(int d1, int d1, ..., int dx)
    {
        X-Array *arr;
        if ((arr = malloc(sizeof(X-Array))) == NULL)
            return NULL;
    
        if ((arr->data = malloc(sizeof(data_type * d1 * d2 * ... * dx))) == NULL)
        {
            free(arr);
            return NULL;
        }
    
        arr->d1 = d1;
        arr->d2 = d2;
        ...
        arr->dx = dx;
    
        return arr;
    }
    

    【讨论】:

    猜你喜欢
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多