[英]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语言中,二维数组只是具有不同索引的常规数组。 因此,您有两个选择:
array[I*n+j]
您可以按照相关文章中所示的方式实现第二个目标: 在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] ) { ... }
我将在下面介绍第二种形式。 请注意,必须先声明rows
和columns
然后才能在VLA声明中使用它们。
您将其称为
int *maxarr = max5( rows, columns, array );
这种方法的优点是:a)很容易,并且b) array
的内存是连续分配的(即,作为一个连续的内存块),并在退出其封闭范围时立即释放; 无需手动free
它。 这种方法的缺点是rows
和columns
不能任意大,您不能使用常规的初始化程序语法来初始化数组(即,您不能编写int array[rows][columns] = { ... };
),并且您不能在文件范围内定义VLA(即,作为全局变量)。 还存在一个问题,即VLA支持始终有些参差不齐,并且2011年标准现在使它们成为可选项,因此不能保证将在所有地方都支持它们。
如果rows
或columns
很大,或者出于某些其他原因要从堆中分配此内存,则稍微复杂一点:
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.