void foo(double **A, double **B) {
    //....
}

int main() {
    double **A;
    double B[10][10];
    int i, j;

    A = (double **)malloc(sizeof(double*) * 10);

    for (i = 0; i < 10; i++) {
        *(A+i) = (double*)malloc(sizeof(double) * 10);
        for (j = 0; j < 10; j++) {
            *(*(A+i)+j) = i * j;
        }
    }

    foo(A, B);

    return 0;
}

这给了我一个警告
warning: incompatible pointer types passing 'double [10][10]' to parameter of type 'double **'
  [-Wincompatible-pointer-types]

据我所知,B持有指向double类型指针的指针。我对A和B做的不是同一件事吗?为什么我只对B做这个警告?

最佳答案

从语法的角度来看,将指针传递给数组和指针传递给指针之间的主要区别并不太难理解。将指针传递到数组时,可以将参数指定为:

somefunc (type array[][y])


somefunc (type (*array)[y])

要去掉的规则——当向数组传递指针时,必须始终传递所涉及的列数。
另一方面,当将指针传递给类型指针时,只需要传递指针。例如。:
somefunc (type **array)

“为什么?”与信息如何存储在内存中有关。以array[x][y]为例。这里有(*array)[y]整数存储在一个连续的内存块中。int array[x][y]x * y为该序列块中的整数提供直接索引。(在每个包含x值的y数组中的任何位置)。
另一方面,使用x,您有一个指向指针的指针——这意味着您的y值标识指向另一个指针的指针,该指针包含int **array值数组的起始地址不要求以任何顺序存储由array[x]yarray[0]标识的任何单独指针。
以下面的例子为例。您拥有array[1](通常所指的典型...或2D数组)和array指向类型指针的数组(典型的双指针)。该示例显示了处理每个传递的不同方式。
游戏中的调整是,一个函数只能返回一个值(一个指针),因此要返回对array[x][y]的引用,必须将其作为一个双指针返回并进行适当的重铸。
#include <stdio.h>
#include <stdlib.h>

#define MAX 5

/* function prototypes */
int **alloc_fill (size_t n);
int **alloc_fill_dp (size_t n);
void prn_array (int (*a)[MAX], size_t nrow);
void prn_array_dp (int **a, size_t nrow, size_t ncol);

int main (int argc, char **argv) {

    int (*array)[MAX] = { NULL };   /* pointer to array of MAX ints */
    int **arraydp = NULL;           /* pointer to pointer to int    */
    size_t i, n;

    n = argc > 1 ? atoi(argv[1]) : 5;   /* set number of rows */

    /* fill 'n' pointer to array[MAX] */
    array   = (int (*)[MAX])alloc_fill (n);

    /* fill 'n' pointer to pointer to int */
    arraydp = alloc_fill_dp (n);

    if (!array || !arraydp ) { /* validate both allocated */
        fprintf (stderr, "error: alloc_fill failed.\n");
        return 1;
    }

    printf ("\n elements of '%zu' arrays:\n\n", n);
    prn_array (array, n);
    printf ("\n elements of '%zu' arrays:\n\n", n);
    prn_array_dp (arraydp, n, MAX);

    free (array);           /* single call to free for 'array' */

    for (i = 0; i < n; i++) /* free each pointer, then arraydp */
        free (arraydp[i]);
    free (arraydp);

    return 0;
}

/* allocate/fill 'n' pointer to array of MAX int */
   int **alloc_fill (size_t n)
{
    int (*a)[MAX] = { NULL };
    size_t i, j;

    if (!(a = calloc (n, sizeof **a * MAX))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return NULL;
    }

    for (i = 0; i < n; i++)
        for (j = 0; j < MAX; j++)
            a[i][j] = (i + 1) * (j + 1);

    return (int **)a;
}

/* allocate/fill 'n' pointer to pointer to type int */
   int **alloc_fill_dp (size_t n)
{
    int **a = NULL;
    size_t i, j;

    /* allocate 'n' pointers */
    if (!(a = calloc (n, sizeof *a))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return NULL;
    }

    for (i = 0; i < n; i++) {
        /* allocate MAX ints */
        if (!(a[i] = calloc (MAX, sizeof **a))) {
            fprintf (stderr, "error: virtual memory exhausted.\n");
            return NULL;
        }
        for (j = 0; j < MAX; j++)
            a[i][j] = (i + 1) * (j + 1);
    }

    return a;
}

/* print function for 'nrow' pointers
 * to array of 'MAX' ints
 */
void prn_array (int (*a)[MAX], size_t nrow)
{
    size_t i,j;

    for (i = 0; i < nrow; i++) {
        for (j = 0; j < MAX; j++)
            printf (" %4d", a[i][j]);
        // putchar ('\n');
        putchar ('\n'), putchar ('\n');
    }
}

/* printf function for 'nrow' pointers
 * to pointer to 'ncol' ints
 */
void prn_array_dp (int **a, size_t nrow, size_t ncol)
{
    size_t i,j;

    for (i = 0; i < nrow; i++) {
        for (j = 0; j < ncol; j++)
            printf (" %4d", a[i][j]);
        // putchar ('\n');
        putchar ('\n'), putchar ('\n');
    }
}

输出
$ ./bin/array_ptr_to_array

 elements of '5' arrays:

    1    2    3    4    5

    2    4    6    8   10

    3    6    9   12   15

    4    8   12   16   20

    5   10   15   20   25


 elements of '5' arrays:

    1    2    3    4    5

    2    4    6    8   10

    3    6    9   12   15

    4    8   12   16   20

    5   10   15   20   25

内存存储差异
在记忆中,这里是橡胶与道路相接的地方。如果您查看下面的内容,您将得到arraydparray[x][y]内存布局的调试器(gdb)描述。注意array所有值都是连续的。但是,对于arraydp,第一个array值是指向组成arraydp值的每个5数组的指针地址。如果随后检查指针地址中的5 int,则可以索引每个单独的值:
arraydp内存中:
(gdb) x/25d array
0x603010:       1       2       3       4
0x603020:       5       2       4       6
0x603030:       8       10      3       6
0x603040:       9       12      15      4
0x603050:       8       12      16      20
0x603060:       5       10      15      20
0x603070:       25

arraydp[0-4]内存中:
(gdb) x/49d arraydp
0x603080:       6303920 0       6303952 0
0x603090:       6303984 0       6304016 0
0x6030a0:       6304048 0       33      0
0x6030b0:       1       2       3       4
0x6030c0:       5       0       33      0
0x6030d0:       2       4       6       8
0x6030e0:       10      0       33      0
0x6030f0:       3       6       9       12
0x603100:       15      0       33      0
0x603110:       4       8       12      16
0x603120:       20      0       33      0
0x603130:       5       10      15      20
0x603140:       25

(gdb) x/5d 6303920
0x6030b0:       1       2       3       4
0x6030c0:       5

(gdb) x/5d 6303952
0x6030d0:       2       4       6       8
0x6030e0:       10

(gdb) x/5d 6303984
0x6030f0:       3       6       9       12
0x603100:       15

(gdb) x/5d 6304016
0x603110:       4       8       12      16
0x603120:       20

(gdb) x/5d 6304048
0x603130:       5       10      15      20
0x603140:       25

从编程的角度来看,这些差异似乎很微妙,但从语法的角度来看,它们是至关重要的。再看一遍,如果你还有问题,请告诉我。

关于c - 将指针传递给函数指针,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34803447/

10-11 23:21
查看更多