二维数组通过指针

时间:2011-12-28 07:18:42

标签: c pointers

我想创建一个存储排列序列的动态数组,例如

order[0][]={1,2,3}
order[1][]={2,1,3}
order[2][]={2,3,1}

假设顺序[m] [n],m =排列数,n =项数,m和n是实时识别的。

我做了以下操作,发现指针地址重叠,导致存储值不正确。如何通过双指针正确使用动态数组?

void permute(int num_permute, int num_term, int** order) {
    int x, y;
    int term[5];

    /* debug only */
    for(y=num_term, x=0; y>0; y--, x++){
        term[x] = y;
    }
    fprintf(stderr, "\n");

    printf("order%12c", ' ');
    for (x=0; x<num_permute; ++x) {
        printf("  %-11d", x);
    }
    printf("\n");
    for(y=0; y<num_permute; y++){
        printf("%-5d%12p", y, (order+y));
        memcpy(&(order[y]), term, sizeof(term));

        for (x=0; x<num_term; x++)
            printf(" %12p", order+y+x);

        printf("\n");

    }
}

int main(){
    int y, z;
    int** x;

    x = (int*) malloc(5*5*sizeof(int*));

    permute(5, 5, x);
    printf("\n");

    printf("x   ");
    for(z=0; z<5; z++){
        printf(" %2d ", z);
    }
    printf("\n");
    for(y=0; y<5; y++){
        printf("%-4d", y);
        for(z=0; z<5; z++){
            printf(" %2d ", *(x+y+z));
        }
        printf("\n");
    }

    free(x);

    return 0;
}

结果:订单[0] [1]和订单[1] [0]指向同一地址......其他人也是如此。以行为主轴,列为次要列:

order             0            1            2            3            4           
0     0x100100080 0x100100080  0x100100084  0x100100088  0x10010008c  0x100100090
1     0x100100084 0x100100084  0x100100088  0x10010008c  0x100100090  0x100100094
2     0x100100088 0x100100088  0x10010008c  0x100100090  0x100100094  0x100100098
3     0x10010008c 0x10010008c  0x100100090  0x100100094  0x100100098  0x10010009c
4     0x100100090 0x100100090  0x100100094  0x100100098  0x10010009c  0x1001000a0

x     0   1   2   3   4 
0     5   5   5   5   5 
1     5   5   5   5   4 
2     5   5   5   4   3 
3     5   5   4   3   2 
4     5   4   3   2   1 

4 个答案:

答案 0 :(得分:4)

源代码:
代码将类似于:

#include <stdlib.h>

int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
     fprintf(stderr, "out of memory\n");
     /*exit or return*/
}
for(i = 0; i < nrows; i++)
{
    array[i] = malloc(ncolumns * sizeof(int));
    if(array[i] == NULL)
    {
          fprintf(stderr, "out of memory\n");
         /*exit or return*/
    }
}

概念:

array是一个指向指针的指针:在第一级,它指向一个指针块,每行一个指针。第一级指针是第一个被分配的指针;它有nrows个元素,每个元素都足以容纳pointer-to-intint *。如果分配成功,则用指针(也从nrows获得)到malloc个数量的指针填充指针(它们的所有ncolumns),该行的存储为阵列。

画报描述:

如果您将情况可视化为:

,则很容易理解

pointers to arrays of pointers as multidimensional arrays

考虑到这一点,示例代码可以重写为:

void permute(int num_permute, int num_term, int** order) {
    int x, y;
    int term[5];
    int* ptr = NULL;

    for (y=num_term, x=0; y>0; y--, x++) {
        term[x] = y;
    }
    printf("\n");

    printf("order%12c", ' ');
    for (x=0; x<num_permute; ++x) {
        printf(" %2d ", x);
    }
    printf("\n");
    for (y=0; y<num_permute; y++) {
        ptr = order[y];
        memcpy(ptr, term, sizeof(term));

        printf("%-5d%12p", y, ptr);
        for (x=0; x<num_term; x++) {
            printf(" %2d ", ptr[x]);
        }
        printf("\n");
    }
}

int main() {
    int y, z;
    int** x = NULL;
    int num_term = 5;
    int num_permutation = 5;
    int* pchk = NULL;

    x = (int**) malloc(num_permutation * sizeof(int*));

    for (y=0; y<num_permutation; y++){
        x[y] = (int*) malloc(num_term * sizeof(int));
        printf("x[%d]: %p\n", y, x[y]);
    }

    permute(num_permutation, num_term, x);

    printf("\nx:  ");
    for(z=0; z<5; z++){
        printf(" %2d ", z);
    }
    printf("\n");

    for(y=0; y<num_permutation; y++){
        pchk = x[y];
        printf("%-4d", y);
        for(z=0; z<num_term; z++){
            printf(" %2d ", pchk[z]);
        }
        printf("\n");
    }

    for (y=0; y<num_permutation; y++) {
        free(x[y]);
    }
    free(x);

    return 0;
}

答案 1 :(得分:2)

代码示例仅模拟多维数组,并且操作不正确。要查看出现了什么问题,首先要考虑在声明多维数组时会发生什么:

int foo[3][5];

这将分配一个大小为3 * 5 * sizeof(int)的连续内存区域。在诸如foo[i]的表达式中,foo被转换为int [5]指针,然后应用索引运算符。换句话说,foo[i]相当于*( (int (*)[5])foo) + i)。每个foo[i]将被视为具有5 * sizeof(int)的大小。

   x,y:  0,0 0,1 0,2 0,3 0,4 1,0 
foo --> | 1 | 2 | 3 | 4 | 5 | 1 |...
        <- 5 * sizeof(int) ->

在示例代码中创建x时,您正在复制此类型的多维数组。您正在使用的索引表达式(*(order + y + x))因此错误,因为它无法正确处理order[y]order + 1 + 0 == order + 0 + 1的大小,这是您在样本输出。

正确的表达式是:(order + num_term * y)用于y th 排列,*(order + num_term * y + x)用于元素order[y][x]

这表明样本中存在另一类错误。对于这种模拟的多维数组,数组类型实际上是指向单维数组的指针。声明的xorder类型应为int*,而不是int**。这应该通过示例代码应该生成的类型警告来加强:

  • x分配空间时,指针的类型(int*)与x
  • 的类型不匹配
  • 打印x的元素时,*(x+y+z)的类型与格式“%d”不匹配。

但是,在模拟多维数组时节省空间,使用时更容易出错(除非您编写一个函数来处理索引)。像Als'这样的解决方案可能更安全,因为您可以使用标准索引操作符。

答案 2 :(得分:1)

如果你有C99(或C11),用指针数组模拟一个2D数组是一个完全的过度杀伤。只需使用

void permute(size_t num_permute, size_t num_term, unsigned order[][num_term]);

作为您的函数签名,并在main中使用

之类的内容分配矩阵
unsigned (*order)[m] = malloc(sizeof(unsigned[n][m]));

另外,正如您在上面的示例中所看到的,我建议您使用语义正确的类型。 size_t最适合使用尺码,您的排列值看起来好像永远不会消极。也许对于这些你也应该从0开始计算。

答案 3 :(得分:0)

以下代码段为给定的行和列创建了一个2d矩阵。请将此作为调试程序的参考。

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

int main()
{
        int row, column;
        int **matrix;
        int i, j, val;

        printf("Enter rows: ");
        scanf("%d", &row);
        printf("Enter columns: ");
        scanf("%d", &column);

        matrix = (int **) malloc (sizeof(int *) * row);
        if (matrix == NULL) {
                printf("ERROR: unable to allocate memory \n");
                return -1;
        }  
        for (i=0 ; i<row ; i++) 
                matrix[i] = (int *) malloc (sizeof(int) * column);

        val=1;
        for (i=0 ; i<row ; i++) {
                for (j=0 ; j<column; j++) {
                        matrix[i][j] = val++;
                }
        }

        for (i=0 ; i<row ; i++) {
                for (j=0 ; j<column; j++) {
                        printf("%3d  ", matrix[i][j]);
                }
                printf("\n");
        }

        return 0;
}

/*
Allocation of 2d matrix with only one call to malloc and 
still get to access the matrix with a[i][j] format

the matrix is divided into headers and data.

headers = metadata to store the rows
data = actual data storage - buffer

allocate one contigious memory for header and data
and then make the elements in the header to point to the data are

        <- headers -----><----------- data -----------

        -----------------------------------------------------------------
        | | | | | |     ..      |
        | | | | | |     ..      |
        -----------------------------------------------------------------
         |                                 ^
         |                                 |
         |-----------------|
        header points to data area

*/

/*
Output:

$ gcc 2darray.c 
$ ./a.out 
Enter rows: 10
Enter columns: 20
  1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20  
 21   22   23   24   25   26   27   28   29   30   31   32   33   34   35   36   37   38   39   40  
 41   42   43   44   45   46   47   48   49   50   51   52   53   54   55   56   57   58   59   60  
 61   62   63   64   65   66   67   68   69   70   71   72   73   74   75   76   77   78   79   80  
 81   82   83   84   85   86   87   88   89   90   91   92   93   94   95   96   97   98   99  100  
101  102  103  104  105  106  107  108  109  110  111  112  113  114  115  116  117  118  119  120  
121  122  123  124  125  126  127  128  129  130  131  132  133  134  135  136  137  138  139  140  
141  142  143  144  145  146  147  148  149  150  151  152  153  154  155  156  157  158  159  160  
161  162  163  164  165  166  167  168  169  170  171  172  173  174  175  176  177  178  179  180  
181  182  183  184  185  186  187  188  189  190  191  192  193  194  195  196  197  198  199  200  
$ 

*/