繁体   English   中英

指向二维数组的指针

[英]Pointer to a 2-D array

拜托,我是C编程的新手,请帮我这个忙。以下代码有错误吗? 基本上,我们如何使用指向二维数组的指针...

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

int* max5(int** p,int r,int c)
{

/* have to design a function which takes as argument pointer to a 2-D array and returns a pointer to an array which contains the 5 highest entries*/

}

int main()

{

    int rows,coloumns;
    printf("Enter the number of rows and coloumns separated by a space\n");
    scanf("%d %d",&rows,&coloumns);
    int **ptr;

    ptr=(int**)malloc(sizeof(int*)*rows);
    int i,j;
    for(i=0;i<rows;i++)
    {
        for(j=0;j<coloumns;j++)
        {
            scanf("%d",*(ptr+i)+j);
            printf("%d\n",*(*(ptr+i)+j));
        }
    }
    free(ptr);
    return 0;
}

在C语言中,二维数组只是具有不同索引的常规数组。 因此,您有两个选择:

  1. 分配一个数组并将其索引为: array[I*n+j]
  2. 分配一个数组数组(这似乎是您试图做的)

您可以按照相关文章中所示的方式实现第二个目标: 在C中分配矩阵

动态分配2D数组可以通过几种方式完成。

假设您有一个支持可变长度数组的C99编译器或C2011编译器,这很简单:

int rows, columns;
...
scanf("%d %d",&rows,&columns);
int array[rows][columns];

array是可变长度数组(VLA),这意味着其尺寸是在运行时确定的。 要将其传递给另一个函数,原型就是

int *max5( int rows, int columns, int arr[rows][columns] ) { ... }

也可以写成

int *max5( int rows, int columns, int (*arr)[columns] ) { ... }

我将在下面介绍第二种形式。 请注意,必须先声明rowscolumns然后才能在VLA声明中使用它们。

您将其称为

int *maxarr = max5( rows, columns, array );

这种方法的优点是:a)很容易,并且b) array的内存是连续分配的(即,作为一个连续的内存块),并在退出其封闭范围时立即释放; 无需手动free它。 这种方法的缺点rowscolumns不能任意大,您不能使用常规的初始化程序语法来初始化数组(即,您不能编写int array[rows][columns] = { ... }; ),并且您不能在文件范围内定义VLA(即,作为全局变量)。 还存在一个问题,即VLA支持始终有些参差不齐,并且2011年标准现在使它们成为可选项,因此不能保证将在所有地方都支持它们。

如果rowscolumns很大,或者出于某些其他原因要从堆中分配此内存,则稍微复杂一点:

int rows, columns;
...
scanf("%d %d", rows, columns);
int (*array)[columns] = malloc( sizeof *array * rows );

在这个版本中, array是一个指向的N元件阵列int (其中N == columns ),并且我们malloc的空间来容纳M个这种阵列(其中,M == rows )。 同样,这利用了VLA语法,但是我们不是从堆栈帧分配内存,而是从堆分配内存。 像第一种方法一样,内存是连续分配的。 您将像其他数组一样索引其中:

array[i][j] = x;

完成数组操作后,您可以将其释放为

free( array );

max5的原型是

int *max5( int rows, int columns, int (*arr)[columns] ) { ... }

看起来熟悉? 那是我们先前通过2D VLA时使用的第二个版本。

除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则类型为“ T N元素数组”的表达式将转换为类型为“”的表达式。指向T “的指针,表达式的值将是数组中第一个元素的地址。

在我们将array声明为2D VLA的第一种情况下,当您调用

int *maxarr = max5( rows, columns, array );

表达array从型转换“ rows的-元素阵列columns -元素的数组int ”到“指针columns -元素的阵列int ”,所以什么max5接收是一个指针值,而不是阵列。 碰巧在函数参数声明的上下文中, T a[N]T a[]都被解释为T *a IOW,三个都声明a作为指向T的指针。

因此,两者

int *max5( int rows, int columns, int arr[rows][columns] ) { ... }

int *max5( int rows, int columns, int (*arr)[columns] ) { ... }

arr声明为指向数组而不是2D数组的指针。 同样,两者都返回一个简单的int * ,而不是一个int数组。 这样做的原因是简单的; 如果您使用返回子数组

return arr[i];

表达arr[i]将具有类型“ columns -元素的阵列int ”; 根据上述规则,该表达式将被转换为int *类型。 C不允许您将数组对象返回为array ,数组表达式也不能成为赋值的目标。

现在,如果您使用的是C89编译器或不支持VLA的C2011编译器,该怎么办? 在这种情况下,您需要以零散的方式分配内存,如下所示:

int rows, columns;
int **array;
...
scanf("%d %d", rows, columns);
array = malloc( sizeof *array * rows );
if ( array )
{
   int i;
   for ( i = 0; i < rows; i++ )
   {
     array[i] = malloc( sizeof *array[i] * columns );
   }
}

现在,您的max5原型为

int *max5( int rows, int columns, int **arr );

您不再处理数组或指向数组的指针; 您正在处理双指针,这与指向2D数组的指针不同。 您仍然可以对其进行下标, 就好像它是2D数组一样

arr[i][j] = x;

但它本身不是数组对象。

要意识到的最重要的事情是,不能保证内存是连续的; 行可能不会在内存中相邻,所以你不想尝试使用指针走行,像这样:

int (*p)[columns] = arr;
while ( some_condition )
  p++; // sets p to point to the next row

对于零散分配的数组,这种算法将不起作用。

另外,由于内存是零散分配的,因此需要零散地释放它:

for ( i = 0; i < rows; i++ )
  free(array[i]);
free( array );

希望能有所帮助。

此代码可解决您的问题:

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

int* max5(int** p,int r,int c)
{

/* have to design a function which takes as argument pointer to a 2-D array and returns a pointer to an array which contains the 5 highest entries*/

}

int main()

{

    int rows,coloumns;
    printf("Enter the number of rows and coloumns separated by a space\n");
    scanf("%d %d",&rows,&coloumns);
    int **ptr;
    int i,j;

    ptr=(int**)malloc(sizeof(int*)*rows);
    for(j=0;j<coloumns;j++)
    {
        *(ptr+j) = (int *)malloc(sizeof(int)*coloumns);
    }

    for(i=0;i<rows;i++)
    {
        for(j=0;j<coloumns;j++)
        {
            scanf("%d",*(ptr+i)+j);
           //*(*(ptr+j)+i) = i+j;
            printf("%d\n",*(*(ptr+i)+j));
        }
    }
    free(ptr);
    return 0;
}

实际上,您忘记为列分配内存!

您可以通过正确定义类型在C中分配2D数组:

int (*ptr)[coloumns] = calloc(sizeof(int) , rows * coloumns);

然后,您可以通过ptr[i][j] 如果您的数组确实需要保留在分配它的范围之外并且很小,那么您也可以在堆栈上分配它

int ptr[rows][coloumns];
memset(ptr, 0, sizeof(ptr));

您试图分配的是一个指针数组int (*)[coloumns]int **类型不同,尽管它们都可以通过使用索引运算符[i][j]进行寻址。 后者的数据结构要复杂得多,并且容易出错。 除非您需要可变的行大小,否则我建议您不要这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM