将指针指向函数指针

时间:2016-01-15 02:31:05

标签: c pointers

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的警告?

3 个答案:

答案 0 :(得分:2)

B是一个10 double的数组数组,与指向double数组的指针数组的类型非常不同。将foo的原型更改为:

void foo(double **A, double (*B)[10])

同样以这种方式简化main中的代码:

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

    A = malloc(10 * sizeof(*A));
    for (i = 0; i < 10; i++) {
        A[i] = malloc(10 * sizeof(*A[i]));
        for (j = 0; j < 10; j++) {
            A[i][j] = i * j;
        }
    }
    foo(A, B);
    return 0;
}

答案 1 :(得分:1)

尝试void foo(double **A, double B[10][10]) 然后传递foo(A, B)

答案 2 :(得分:1)

从语法角度将指针传递给数组指针指向之间的主要区别并不难理解。当您将指针传递给数组array[x][y](*array)[y]时,您可以将参数指定为:

somefunc (type array[][y])

somefunc (type (*array)[y])

要带走的规则 - 在将指针传递给数组时,必须始终传递所涉及的列数。

另一方面,当将指针指向类型时,只需传递指针即可。 e.g:

somefunc (type **array)

为什么?”的主要区别在于如何将信息存储在内存中。以int array[x][y]为例。在那里,你有x * y个整数存储在一个连续的内存块中。 xy为该顺序块中的整数提供直接索引。 (x数组中的任何位置,每个数组都包含y个值。

另一方面,使用int **array,您有一个指针指针 - 意味着您的array[x]值标识指向另一个指针的点,该指针包含y数组的起始地址值。不要求array[0]array[1]...标识的任何单独指针都以任何顺序方式存储。

采用以下示例。您有array(典型的array[x][y]或2D数组,因为它经常被引用)和arraydp数组的指向指针的类型 (典型的双指针)。该示例显示了必须处理每种方式的不同方式。

游戏中的调整是一个函数只能返回一个值(一个指针),所以要返回一个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

内存中存储的差异

在记忆中,橡胶与道路相遇。我看下面,您有gdbarray的内存布局的调试器(arraydp)描述。注意array所有值都是顺序的。但是,对于arraydp,第一个5值是指针地址,指向构成5 int值的各个arraydp数组。然后,如果您检查arraydp[0-4]的指针地址,则可以为每个单独的值编制索引:

内存中的

array

(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

(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

从编程的角度来看,差异可能看起来微妙,但从语法角度来看,它们是至关重要的。仔细看看,如果您有其他问题,请告诉我。