Pertanyaan Melewati susunan tiga dimensi ke fungsi dalam C


Saya menggunakan program dengan FORTRAN, tetapi saya memutuskan untuk belajar C dan C++. Saya mulai dengan C bahasa, dan satu hal yang saya tidak pernah gunakan adalah pointer, karena FORTRAN berikan nilai berdasarkan referensi. Saya membuat kode contoh di bawah ini untuk memahami cara kerja pointer dengan array multidimensional:

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

#define DIM1 3
#define DIM2 2 
#define DIM3 4

void display3DArray1(int, int , int n, int (*arr)[][n]);
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]);

int main(void)
{
    int matrix3D[DIM1][DIM2][DIM3] = {
        {{1, 2, 3, 4}, {5, 6, 7, 8}},
        {{9, 10, 11, 12}, {13, 14, 15, 16}},
        {{17, 18, 19, 20}, {21, 22, 23, 24}}
    };
    int (*pmatrix3D)[DIM2][DIM3] = matrix3D;

    display3DArray1(DIM1, DIM2, DIM3,pmatrix3D); 
    display3DArray2(DIM1, DIM2, DIM3,pmatrix3D); 

    return 0;
}

void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2]) {
    printf("\n");
    for(int i=0; i<rows; i++) {
        for(int j=0; j<cols1; j++) {
            for(int k=0; k<cols2; k++) {
                printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);
            }
        }
    }
}

void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
    printf("\n");
    for(int i=0; i<rows; i++) {
        for(int j=0; j<cols1; j++) {
            for(int k=0; k<cols2; k++) {
                printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;
            }
        }
    }
}

Kode bekerja, tetapi ada sesuatu yang saya tidak dapat mengerti. Ketika saya mencoba menggunakan yang kedua printf dari fungsi kedua di yang pertama saya mendapatkan kesalahan kompilasi:

"penggunaan tidak valid array dengan batas yang tidak ditentukan" - di bawah gcc.

Mengapa *(arr + i) tidak berfungsi di fungsi pertama?


6
2017-11-28 13:17


asal


Jawaban:


Anda dapat menggunakan dua cara berikut untuk meneruskan / mencetak matriks:

void display3DArray1(int rows, int cols1, int cols2, int *A) {
    int *a, i, j, k;
    printf("\n");
    for(i=0; i<rows; i++) {
        for(j=0; j<cols1; j++) {
            for(k=0; k<cols2; k++) {
                a= A+(i*cols1*cols2)+(j*cols2)+k;
                printf("%d, %p\n", *a, a);
            }
        }
    }
}

void display3DArray2(int A[DIM1][DIM2][DIM3]) {
    int i, j, k;
    printf("\n");
    for(i=0; i<DIM1; i++) {
        for(j=0; j<DIM2; j++) {
            for(k=0; k<DIM3; k++) {
                printf("%d, %p\n", A[i][j][k], &A[i][j][k]);
            }
        }
    }
}

Metode pertama tidak bergantung pada dimensi matriks; yang kedua tidak. Akibatnya, yang pertama membutuhkan perhitungan alamat eksplisit (baris saya, col jsel k).

Gunakan panggilan masing-masing:

display3DArray1(DIM1, DIM2, DIM3, (int *)matrix3D);
display3DArray2(matrix3D);

Perhatikan para pemain dari matriks ke pointer int.

Dalam kode Anda, Anda menggunakan nama parameter untuk menentukan dimensi matriks. Dalam versi C saya, itu tidak legal; mereka pasti konstanta.


2
2017-11-28 13:43



Hanya pelengkap jawaban Paul Ogilvie.

Penggunaan yang benar dari Variable Length Arrays adalah:

void display3DArray3(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
    printf("\n");
    for(int i=0; i<rows; i++) {
        for(int j=0; j<cols1; j++) {
            for(int k=0; k<cols2; k++) {
                printf("*arr : %d adress: %p\n", arr[i][j][k], &arr[i][j][k]);
            }
        }
    }
}

2
2017-11-28 13:58



Saya sedikit bingung, jujur. Masalah utamanya adalah bahwa deklarasi parameter fungsi seperti di f(T arr[]) menyatakan jenis yang tidak lengkap yang ukurannya tidak diketahui (baik pada waktu kompilasi maupun pada saat run time). Awalnya saya pikir kurung kosong kosong di deklarasi parameter fungsi hanya menyatakan pointer - notasi meskipun -, tapi itu tidak terjadi. Parameter masih memiliki tipe array, meskipun tidak lengkap.1

Ketika Anda menulis

void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2])

Anda menyatakan a penunjuk untuk jenis yang tidak lengkap dari ukuran yang tidak diketahui. Penunjuk ini tidak dapat dimanipulasi dengan cara biasa; khususnya, menambahkannya untuk melompat ke elemen berikutnya tidak mungkin karena kita tidak tahu di mana elemen saat ini berakhir (dan karenanya elemen berikutnya dimulai). Tetapi Anda mencobanya

printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;

dengan yang terdalam arr+1. Hanya dereferencing itu berhasil, karena variabel itu menyimpan alamat dari elemen pertama baik-baik saja. Inilah yang dicetak dalam fungsi pertama:

 printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);

dengan *arr. Itu ukuran elemen  dari array tidak lengkap yang arr poin diketahui (elemen ini adalah larik dari cols2 ints), sehingga kami dapat menambah *arr, bahkan jika kita tidak bisa menambahkannya arr  layak.

Untuk kelengkapan: Mengapa Anda dapat mengakses arr seperti itu di fungsi kedua? Baik:

void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2])

menyatakan arr sebagai jenis larik yang tidak lengkap, benar; tetapi ukuran dari elemen-elemennya sudah sangat dikenal: yaitu matriks-matriks cols1 x cols2 int. Deklarasi itu tidak menyebutkan berapa banyak yang ada di sana, tetapi kita pasti bisa mengiterasi mereka jika kita tahu kapan harus berhenti.


1 Tentu saja susunan ini, seperti yang lain, "meluruh" menjadi penunjuk di sebagian besar konteks, sehingga informasi jenis yang hilang tidak menjadi masalah. Tetapi itu penting jika kita memiliki petunjuk kepada mereka.


1
2017-11-28 14:42



Pengindeksan array Anda dalam rutinitas 'cetak' tidak valid. Deklarasi 'matrix3D' menyiratkan bahwa jenis dari nama itu adalah 'penunjuk ke int'. CATATAN: Hanya satu tingkat tipuan di sana. Ekspresi pengindeksan memiliki banyak ''-s di depan istilah; di C itu berarti 'item di sebelah kanan''adalah pointer yang harus dereferenced untuk mendapatkan nilai'. Itu berarti Anda pada efeknya memperlakukan 'matrix3D' sebagai 'pointer ke (pointer ke (pointer ke int))' yang terlalu banyak tipuan.


-2
2017-11-28 13:48