使用C中的指针逐步执行多维数组

时间:2015-10-14 04:40:14

标签: c arrays pointers multidimensional-array

作为练习,我正在尝试构建一个随机整数的二维数组。我想通过使用指针算法迭代数组来分配随机数。

我认为我遇到了以下For循环的问题,我从C编程的P268中取得了King。

int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1] [NUM_COLUMNS - 1]; p++)

我正在尝试在我自己的程序中使用类似的循环,但该程序似乎没有分配任何值。

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

int ** make_array(int in_size );
void read_array( int ** a, int n);

int main(void){
        int size;
        int **p;

        size = 5;
        p = make_array( size );
        read_array( p, size );

        return 0;
}

int ** make_array( int in_size ) {
        int i,  *p, **a;

        srand ((unsigned)time(NULL));

        a = malloc(in_size * sizeof(int*));
        for (i = 0; i < in_size ; i++) {
              a[i] = malloc( in_size * sizeof(int));
        }

        for (p = &a[0][0]; p <= &a[in_size -1 ][in_size - 1]; p++) {
                *p = rand() % 10;
        }

        return a;

}

void read_array( int **a, int n ) {
        int i, *p;
        for (p = &a[0][0] ; p <= &a[n - 1][n - 1]; p++)
                printf("%d ", *p );
}

现在我知道我可以使用嵌套for循环很容易地遍历它,这似乎是一种循环遍历数组的优雅方式。知道我做错了吗?

2 个答案:

答案 0 :(得分:3)

int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1] [NUM_COLUMNS - 1]; p++)

在两种情况下有效:
(1)当'a'被定义为二维数组时,例如int [NUM_ROWS] [NUM_COLUMNS]。在这种情况下,内存块是连续的,因此,使用指针变量迭代2D数组元素是有效的。

(2)按如下方式修改make_array()函数,以分配连续的内存块以使用上述方法。

int ** make_array( int in_size ) 
{
        int i,  *p, **a;
        int *big_chunk;

        srand ((unsigned)time(NULL));

        a = (int **)malloc(in_size * sizeof(int*));
        big_chunk = (int *)malloc(in_size * in_size * sizeof(int));  <-- change done here
        for (i = 0; i < in_size ; i++) 
        {
              a[i] = big_chunk + i * insize;                         <-- change done here
        }

        /* Other code */
}

在原始的make_array()函数中,malloc()不保证在malloc()调用的连续迭代中连续的内存块。因此,使用指针迭代2D数组元素将是不正确的。例如一旦'p'达到[0] [in_size-1],则p =&amp; a [0] [in_size]将不同于[1] - &gt;第二行的malloc地址。

答案 1 :(得分:2)

如您所知,在C中,有没有 2D数组。只有方法可以模拟2D数组的索引。它们分为两类,(1)创建指向数组的指针数组,以及(2)创建正常的顺序数组并使用索引算法以2D方式引用元素。在每种情况下,可以根据数组中元素的总数(或数组的size)以及要模拟的列数(或stride)来考虑算术。阵列。通过仔细索引,了解数组的sizestride,您可以将C-1D数组用作2D数组。为了帮助完成解决与这两种类型以及指针和索引的使用有关的任何问题,请考虑以下事项:

要输入的指针数组

首先,当您使用指针数组(例如int **array)时,您将ROWS个指针分配给COLS大小的类型数组(基本上你有ROWSCOLS个大小的数组。)然后通过取消引用,你可以将你的元素索引为一个二维数组(例如array[0][x],其中0 <= x < COLS读取所有数组。第一个指针指向的数组array[1][x],第二个指针,依此类推......)。

要分配指向要键入的指针数组,您需要分配ROWS个指针数(其中ROWS等同于size/stride):

    int **array = NULL;
    ...
    array = xcalloc (size/stride, sizeof *array);

注意: xcalloc只是一个使用calloc并使用错误检查来验证分配的函数。

在分配ROWS个指针后,为每个原始指针分配一个单独的{@ 1}}(或COLS}个元素列数组。

stride

将指针数组分配给type后,您将使用两个循环来填充/操作数组中的数据:

    for (i = 0; i < size/stride; i++)
        array[i] = xcalloc (stride, sizeof **array);

您可以使用简单的 for (i = 0; i < size/stride; i++) for (j = 0; j < stride; j++) array[i][j] = rand() % 1000; 语法访问任何单个成员。请注意,您只需将array[i][j]视为size/stride,将ROWS视为stride,因此,如果您计算COLSROWS的值,可以写上面的内容:

COLS

线性阵列作为二维阵列处理

由于在这种情况下使用传统的顺序1D数组来保存数据,因此声明和分配数组非常简单:

    for (i = 0; i < ROWS; i++)
        for (j = 0; j < COLS; j++)
            array[i][j] = rand() % 1000;

注意:以模拟的2D方式访问数组的元素,您必须使用您将用于访问值的相同逻辑将值存储在数组中,这从循环的角度来看将与您在上面的数组指针中所做的完全相同。唯一的区别是索引的计算:

    int *array = NULL;
    ...
    array = xcalloc (size, sizeof *array);

在这里,需要仔细研究如何模拟array [i] [j]访问。注意:数组的索引:

    for (i = 0; i < size/stride; i++)
        for (j = 0; j < stride; j++)
            array[i * stride + j] = rand() % 1000;

当您拥有线性一维元素数组时,允许您以二维方式处理和访问值的索引由 array[i * stride + j] = rand() % 1000; 给出,array[i * stride + j]i表示{{1} }和j

将所有这些放在几个例子中,将向您展示所有部分如何组合在一起:

示例 - 要键入的指针数组

ROWS

示例使用/输出

COLS

示例 - 处理为二维阵列的线性阵列

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

void *xcalloc (size_t n, size_t s);

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

    int **array = NULL;
    int size   = argc > 1 ? (int)strtol(argv[1], NULL, 10) : 36;
    int stride = argc > 2 ? (int)strtol(argv[2], NULL, 10) : 6;
    int i,j;

    /* test valid size/stride */
    if (size < stride || size % stride) {
        fprintf (stderr, "error: invalid stride '%d' for %d element array.\n",
                stride, size);
        return 1;
    }

    srand (time(NULL)); /* initialize seed */

    /* alloc array of pointers to array of integers in memory */
    array = xcalloc (size/stride, sizeof *array);

    /* allocate arrays of integers */
    for (i = 0; i < size/stride; i++)
        array[i] = xcalloc (stride, sizeof **array);

    /* fill with random values */
    for (i = 0; i < size/stride; i++)
        for (j = 0; j < stride; j++)
            array[i][j] = rand() % 1000;

    /* printing in simulated 2D format */
    printf ("\n printing (%d x %d) array\n\n",
            size/stride, stride);

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

    /* print a particular element array[1][2] */
    if (stride > 1)
        printf ("\n array[1][1] in (%d x %d) array : %d\n\n",
                size/stride, stride, array[1][1]);

    /* free allocated memory */
    for (i = 0; i < size/stride; i++)
        free (array[i]);
    free (array);

    return 0;
}

/** xcalloc allocates memory using calloc and validates the return.
 *  xcalloc allocates memory and reports an error if the value is
 *  null, returning a memory address only if the value is nonzero
 *  freeing the caller of validating within the body of code.
 */
void *xcalloc (size_t n, size_t s)
{
    register void *memptr = calloc (n, s);
    if (memptr == 0)
    {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }

    return memptr;
}

使用/输出

$ ./bin/array_stride_2d 12 2

 printing (6 x 2) array

  535   68
   45  815
  348  480
  417  151
  443  789
  267  738

 array[1][1] in (6 x 2) array : 815

$ ./bin/array_stride_2d 12 3

 printing (4 x 3) array

  841  195  147
  870   18  892
  624  516  820
  250  769  532

 array[1][1] in (4 x 3) array : 18

$ ./bin/array_stride_2d 12 4

 printing (3 x 4) array

  116  275  740  510
  625  122  386  623
  624  879  970  396

 array[1][1] in (3 x 4) array : 122

$ ./bin/array_stride_2d 12 6

 printing (2 x 6) array

  543  631  562  504  307  940
  932   75  225  662  181  990

 array[1][1] in (2 x 6) array : 75

内存错误检查

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

void *xcalloc (size_t n, size_t s);

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

    int *array = NULL;
    int size   = argc > 1 ? (int)strtol(argv[1], NULL, 10) : 36;
    int stride = argc > 2 ? (int)strtol(argv[2], NULL, 10) : 6;
    int i,j;

    /* test valid size/stride */
    if (size < stride || size % stride) {
        fprintf (stderr, "error: invalid stride '%d' for %d element array.\n",
                stride, size);
        return 1;
    }

    srand (time(NULL)); /* initialize seed */

    /* alloc array of size sequential in memory */
    array = xcalloc (size, sizeof *array);

    /* fill with random values */
    for (i = 0; i < size/stride; i++)
        for (j = 0; j < stride; j++)
            array[i * stride + j] = rand() % 1000;

    /* printing in simulated 2D format */
    printf ("\n printing (%d x %d) array\n\n",
            size/stride, stride);

    for (i = 0; i < size/stride; i++) {
        for (j = 0; j < stride; j++)
            printf (" %4d", array[i * stride + j]);
        putchar ('\n');
    }

    /* print a particular element array[1][2] */
    if (stride > 1)
        printf ("\n array[1][1] in (%d x %d) array : %d\n\n",
                size/stride, stride, array[1 * stride + 1]);

    free (array);

    return 0;
}

/** xcalloc allocates memory using calloc and validates the return.
 *  xcalloc allocates memory and reports an error if the value is
 *  null, returning a memory address only if the value is nonzero
 *  freeing the caller of validating within the body of code.
 */
void *xcalloc (size_t n, size_t s)
{
    register void *memptr = calloc (n, s);
    if (memptr == 0)
    {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }

    return memptr;
}

希望这对您的学习有所帮助,基本上有两种方案可以将数组视为C中的2D数组。您甚至可以更有创意并创建超出2D的维数组,只需注意索引计算很快就会变得多一点参与其中。即使在2D级别,您也可以从这些方法中获得更多,例如行和列向量,上/下矩阵,矩阵算法等。如果您有任何问题,请告诉我。