簡體   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