Truyền một mảng 2D cho hàm C ++


324

Tôi có một hàm mà tôi muốn lấy, như một tham số, một mảng 2D có kích thước thay đổi.

Cho đến nay tôi có điều này:

void myFunction(double** myArray){
     myArray[x][y] = 5;
     etc...
}

Và tôi đã khai báo một mảng ở nơi khác trong mã của mình:

double anArray[10][10];

Tuy nhiên, gọi myFunction(anArray)cho tôi một lỗi.

Tôi không muốn sao chép mảng khi tôi chuyển nó vào. Mọi thay đổi được thực hiện myFunctionsẽ làm thay đổi trạng thái của anArray. Nếu tôi hiểu chính xác, tôi chỉ muốn truyền vào như một đối số một con trỏ tới một mảng 2D. Hàm cũng cần chấp nhận các mảng có kích thước khác nhau. Vì vậy, ví dụ, [10][10][5][5]. Tôi có thể làm cái này như thế nào?


1
không thể chuyển đổi tham số 3 từ 'double [10] [10]' thành 'double **'
RogerDarwin

3
Các câu trả lời được chấp nhận chương trình chỉ có 2 kỹ thuật [của nó (2)(3) đều giống nhau] nhưng đang có 4 cách độc đáo của đi qua một mảng 2D sang một chức năng .
huyền thoại2k

Nói đúng ra, vâng, chúng không phải là mảng 2D, nhưng quy ước này (mặc dù dẫn đến UB) về việc có một mảng các con trỏ, mỗi mảng trỏ đến (một mảng 1D), dường như rất phổ biến :( Có một mảng 1D phẳng của mxn độ dài, với các hàm / lớp của trình trợ giúp để mô phỏng một mảng 2D có lẽ tốt hơn
legends2k

DỄ DÀNG - func(int* mat, int r, int c){ for(int i=0; i<r; i++) for(int j=0; j<c; j++) printf("%d ", *(mat+i*c+j)); }. Gọi nó như-int mat[3][5]; func(mat[0], 3, 5);
Minhas Kamal

Câu trả lời:


413

Có ba cách để truyền một mảng 2D cho một hàm:

  1. Tham số là một mảng 2D

    int array[10][10];
    void passFunc(int a[][10])
    {
        // ...
    }
    passFunc(array);
    
  2. Tham số này là một mảng chứa con trỏ

    int *array[10];
    for(int i = 0; i < 10; i++)
        array[i] = new int[10];
    void passFunc(int *a[10]) //Array containing pointers
    {
        // ...
    }
    passFunc(array);
    
  3. Tham số là con trỏ tới con trỏ

    int **array;
    array = new int *[10];
    for(int i = 0; i <10; i++)
        array[i] = new int[10];
    void passFunc(int **a)
    {
        // ...
    }
    passFunc(array);
    

4
@Overflowh Bạn có thể nhận được các yếu tố arrayvới array[i][j]:)
shengy

14
Đối với trường hợp 1, tham số có thể được khai báo là int (*a)[10].
Zachary

9
Đối với trường hợp thứ 2, tham số có thể được khai báo là int **.
Zachary

1
@Zack: Bạn nói đúng, thực sự chỉ có hai trường hợp; một là một con trỏ tới con trỏ và khác là một con trỏ tới một mảng nguyên có kích thước n tức là int (*a) [10].
huyền thoại2k

3
Trường hợp 2 và 3 không phải là mảng 2D, vì vậy câu trả lời này là sai lệch. Xem này .
Lundin

178

Kích thước cố định

1. Đi qua tham khảo

template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

Trong C ++, truyền mảng bằng tham chiếu mà không làm mất thông tin kích thước có lẽ là an toàn nhất, vì người ta không cần lo lắng về việc người gọi chuyển một thứ nguyên không chính xác (cờ trình biên dịch khi không khớp). Tuy nhiên, điều này là không thể với các mảng động (freestore); nó chỉ hoạt động cho các mảng tự động ( thường là ngăn xếp ), tức là kích thước nên được biết đến tại thời điểm biên dịch.

2. Đi bằng con trỏ

void process_2d_array_pointer(int (*array)[5][10])
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < 5; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < 10; ++j)
            std::cout << (*array)[i][j] << '\t';
        std::cout << std::endl;
    }    
}

Tương đương C của phương thức trước đó là truyền mảng bằng con trỏ. Không nên nhầm lẫn với việc chuyển qua loại con trỏ bị phân rã của mảng (3) , đây là phương pháp phổ biến, phổ biến, mặc dù ít an toàn hơn phương pháp này nhưng linh hoạt hơn. Giống như (1) , sử dụng phương pháp này khi tất cả các kích thước của mảng được cố định và được biết tại thời gian biên dịch. Lưu ý rằng khi gọi hàm, địa chỉ của mảng phải được truyền process_2d_array_pointer(&a)và không phải là địa chỉ của phần tử đầu tiên bằng cách phân rã process_2d_array_pointer(a).

Kích thước thay đổi

Chúng được kế thừa từ C nhưng kém an toàn hơn, trình biên dịch không có cách nào kiểm tra, đảm bảo rằng người gọi sẽ vượt qua các kích thước yêu cầu. Hàm chỉ ngân hàng về những gì người gọi chuyển qua dưới dạng thứ nguyên. Chúng linh hoạt hơn các loại trên vì các mảng có độ dài khác nhau có thể được truyền cho chúng một cách bất biến.

Cần nhớ rằng không có thứ gì truyền trực tiếp một mảng vào hàm trong C [trong khi ở C ++, chúng có thể được truyền dưới dạng tham chiếu (1) ]; (2) đang truyền một con trỏ tới mảng chứ không phải chính mảng đó. Luôn luôn truyền một mảng như là trở thành một hoạt động sao chép con trỏ, được tạo điều kiện thuận lợi bởi bản chất phân rã của mảng thành một con trỏ .

3. Chuyển qua (giá trị) một con trỏ đến loại đã phân rã

// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < 10; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

Mặc dù int array[][10]được cho phép, tôi không khuyến nghị sử dụng cú pháp trên vì cú pháp trên cho thấy rõ rằng định danh arraylà một con trỏ duy nhất cho một mảng gồm 10 số nguyên, trong khi cú pháp này trông giống như một mảng 2D nhưng là cùng một con trỏ một mảng gồm 10 số nguyên. Ở đây chúng ta biết số lượng phần tử trong một hàng (tức là kích thước cột, 10 ở đây) nhưng số lượng hàng không xác định và do đó được chuyển qua làm đối số. Trong trường hợp này có một số an toàn vì trình biên dịch có thể gắn cờ khi con trỏ tới một mảng có kích thước thứ hai không bằng 10 được thông qua. Kích thước đầu tiên là phần khác nhau và có thể được bỏ qua. Xem ở đây để biết lý do tại sao chỉ có kích thước đầu tiên được phép bỏ qua.

4. Chuyển bằng con trỏ đến một con trỏ

// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
    std::cout << __func__ << std::endl;
    for (size_t i = 0; i < rows; ++i)
    {
        std::cout << i << ": ";
        for (size_t j = 0; j < cols; ++j)
            std::cout << array[i][j] << '\t';
        std::cout << std::endl;
    }
}

Một lần nữa, có một cú pháp thay thế int *array[10]giống như int **array. Trong cú pháp này, [10]nó bị bỏ qua khi nó phân rã thành một con trỏ do đó trở thành int **array. Có lẽ nó chỉ là một gợi ý cho người gọi rằng mảng đã qua phải có ít nhất 10 cột, thậm chí sau đó cần có số hàng. Trong mọi trường hợp, trình biên dịch không gắn cờ cho bất kỳ vi phạm chiều dài / kích thước nào (nó chỉ kiểm tra xem kiểu được truyền có phải là con trỏ tới con trỏ không), do đó yêu cầu cả số hàng và số cột là tham số có ý nghĩa ở đây.

Lưu ý: (4) là tùy chọn ít an toàn nhất vì hầu như không có bất kỳ loại kiểm tra nào và bất tiện nhất. Một cách hợp pháp không thể chuyển một mảng 2D cho chức năng này; C-FAQ lên án cách giải quyết thông thường khi thực hiện int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);vì nó có thể dẫn đến hành vi không xác định do làm phẳng mảng. Cách truyền đúng một mảng trong phương thức này đưa chúng ta đến phần bất tiện, tức là chúng ta cần một mảng con trỏ bổ sung (thay thế) với mỗi phần tử của nó trỏ đến hàng tương ứng của mảng thực tế được truyền; thay thế này sau đó được chuyển đến chức năng (xem bên dưới); tất cả điều này để có được cùng một công việc được thực hiện như các phương pháp trên an toàn hơn, sạch hơn và có lẽ nhanh hơn.

Đây là một chương trình trình điều khiển để kiểm tra các chức năng trên:

#include <iostream>

// copy above functions here

int main()
{
    int a[5][10] = { { } };
    process_2d_array_template(a);
    process_2d_array_pointer(&a);    // <-- notice the unusual usage of addressof (&) operator on an array
    process_2d_array(a, 5);
    // works since a's first dimension decays into a pointer thereby becoming int (*)[10]

    int *b[5];  // surrogate
    for (size_t i = 0; i < 5; ++i)
    {
        b[i] = a[i];
    }
    // another popular way to define b: here the 2D arrays dims may be non-const, runtime var
    // int **b = new int*[5];
    // for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
    process_pointer_2_pointer(b, 5, 10);
    // process_2d_array(b, 5);
    // doesn't work since b's first dimension decays into a pointer thereby becoming int**
}

Điều gì về việc chuyển các mảng được phân bổ động cho các hàm trong C ++? Trong tiêu chuẩn C11, nó có thể được thực hiện cho các mảng được phân bổ tĩnh và động như fn (int col, int row, int mảng [col] [row]): stackoverflow.com/questions/16004668/. Tôi đã đặt câu hỏi cho vấn đề này : stackoverflow.com/questions/27457076/ cấp
42n4

@ 42n4 Trường hợp 4 bao gồm (đối với C ++). Đối với các mảng được phân bổ động, chỉ có dòng bên trong vòng lặp sẽ thay đổi từ b[i] = a[i];thành, giả sử , b[i] = new int[10];. Người ta cũng có thể bphân bổ động int **b = int *[5];và nó vẫn hoạt động như bình thường.
huyền thoại2k

1
Làm thế nào để giải quyết array[i][j]công việc vào chức năng trong 4) ? Bởi vì nó đã nhận được ptr đến ptr và không biết giá trị của thứ nguyên cuối cùng, điều cần thiết để thực hiện thay đổi cho địa chỉ chính xác?
user1234567 16/12/14

2
array[i][j]chỉ là số học của con trỏ, tức là với giá trị của con trỏ array, nó sẽ thêm ivà bổ sung kết quả như là int*, nó sẽ thêm jvà bổ sung vị trí đó, đọc một int. Vì vậy, không, nó không cần biết bất kỳ chiều nào cho việc này. Nhưng, đó là toàn bộ vấn đề! Trình biên dịch lấy từ của lập trình viên trong đức tin và nếu lập trình viên không chính xác, hành vi không xác định xảy ra. Đây là lý do tôi đã đề cập rằng trường hợp 4 là lựa chọn an toàn nhất.
huyền thoại2k

Trong những trường hợp như vậy, một cấu trúc có thể phục vụ bạn tốt.
Xofo

40

Một sửa đổi cho đề xuất đầu tiên của shengy, bạn có thể sử dụng các mẫu để làm cho hàm chấp nhận một biến mảng đa chiều (thay vì lưu trữ một mảng các con trỏ phải được quản lý và xóa):

template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
    printf("%p\n", &arr);
}

int main()
{
    double a1[10][10];
    double a2[5][5];

    printf("%p\n%p\n\n", &a1, &a2);
    func(a1);
    func(a2);

    return 0;
}

Các câu lệnh in ở đó để chỉ ra rằng các mảng đang được truyền bằng tham chiếu (bằng cách hiển thị địa chỉ của các biến)


2
Bạn nên sử dụng %pđể in một con trỏ và thậm chí sau đó, bạn phải chuyển nó sang void *, nếu không printf()sẽ gọi hành vi không xác định. Hơn nữa, bạn không nên sử dụng &toán tử addressof ( ) khi gọi các hàm, vì các hàm mong đợi một đối số kiểu double (*)[size_y], trong khi bạn hiện vượt qua chúng double (*)[10][10]double (*)[5][5].

Nếu bạn đang sử dụng các mẫu làm cho cả hai chiều làm đối số mẫu là phù hợp hơn và tốt hơn vì có thể tránh hoàn toàn truy cập con trỏ mức thấp.
huyền thoại2k

3
Điều này chỉ hoạt động nếu kích thước của mảng được biết tại thời gian biên dịch.
jeb_is_a_mess

@Georg Mã ở trên trong câu trả lời là chính xác những gì tôi đã đề xuất. Nó hoạt động trong GCC 6.3 - bản demo trực tuyến . Bạn đã quên làm cho tham số tham chiếu?
huyền thoại2k

21

Ngạc nhiên là chưa có ai đề cập đến vấn đề này, nhưng bạn chỉ có thể tạo mẫu trên bất kỳ thứ gì hỗ trợ 2D [] [] ngữ nghĩa.

template <typename TwoD>
void myFunction(TwoD& myArray){
     myArray[x][y] = 5;
     etc...
}

// call with
double anArray[10][10];
myFunction(anArray);

Nó hoạt động với bất kỳ cơ sở hạ tầng "giống như mảng" 2D nào, chẳng hạn như std::vector<std::vector<T>>, hoặc loại do người dùng xác định để tối đa hóa việc sử dụng lại mã.


1
Đây phải là câu trả lời đúng. Nó giải quyết tất cả các vấn đề được đề cập và một số vấn đề không được đề cập ở đây. Loại an toàn, không tương thích thời gian biên dịch của mảng, không có số học con trỏ, không đúc kiểu, không sao chép dữ liệu. Hoạt động cho C và C ++.
OpalApps

Vâng, điều này hoạt động cho C ++; C không hỗ trợ các mẫu. Làm điều đó trong C sẽ yêu cầu macro.
Gunnar

20

Bạn có thể tạo một mẫu hàm như thế này:

template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
    myArray[x][y] = 5;
    etc...
}

Sau đó, bạn có cả hai kích thước kích thước thông qua R và C. Một chức năng khác nhau sẽ được tạo cho từng kích thước mảng, vì vậy nếu chức năng của bạn lớn và bạn gọi nó với nhiều kích thước mảng khác nhau, điều này có thể tốn kém. Bạn có thể sử dụng nó như một trình bao bọc cho một chức năng như thế này:

void myFunction(double * arr, int R, int C)
{
    arr[x * C + y] = 5;
    etc...
}

Nó coi mảng là một chiều và sử dụng số học để tìm ra các độ lệch của các chỉ mục. Trong trường hợp này, bạn sẽ xác định mẫu như thế này:

template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
    myFunction(*myArray, R, C);
}

2
size_tlà loại tốt hơn cho các chỉ mục mảng hơn int.
Andrew Tomazos

13

anArray[10][10]không phải là một con trỏ tới một con trỏ, nó là một đoạn bộ nhớ liền kề phù hợp để lưu trữ 100 giá trị của kiểu double, trình biên dịch này biết cách xử lý vì bạn đã chỉ định kích thước. Bạn cần truyền nó cho một hàm dưới dạng một mảng. Bạn có thể bỏ qua kích thước của kích thước ban đầu, như sau:

void f(double p[][10]) {
}

Tuy nhiên, điều này sẽ không cho phép bạn vượt qua các mảng có thứ nguyên cuối cùng ngoài mười.

Giải pháp tốt nhất trong C ++ là sử dụng std::vector<std::vector<double> >: nó gần như hiệu quả và tiện lợi hơn đáng kể.


1
Tôi thích giải pháp này vì thư viện std rất hiệu quả - bằng cách tôi thích dasblinkenlight; Tôi đã từng sử dụng dasblikenlicht
mozillanerd

Gần như hiệu quả? Vâng đúng. Đuổi theo con trỏ luôn đắt hơn so với đuổi theo con trỏ.
Thomas Eding

8

Mảng một chiều phân rã thành một con trỏ con trỏ trỏ đến phần tử đầu tiên trong mảng. Trong khi một mảng 2D phân rã thành một con trỏ trỏ đến hàng đầu tiên. Vì vậy, nguyên mẫu hàm phải là -

void myFunction(double (*myArray) [10]);

Tôi thích std::vectorhơn mảng thô.


8

Bạn có thể làm một cái gì đó như thế này ...

#include<iostream>

using namespace std;

//for changing values in 2D array
void myFunc(double *a,int rows,int cols){
    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++){
            *(a+ i*rows + j)+=10.0;
        }
    }
}

//for printing 2D array,similar to myFunc
void printArray(double *a,int rows,int cols){
    cout<<"Printing your array...\n";
    for(int i=0;i<rows;i++){
        for(int j=0;j<cols;j++){
            cout<<*(a+ i*rows + j)<<"  ";
        }
    cout<<"\n";
    }
}

int main(){
    //declare and initialize your array
    double a[2][2]={{1.5 , 2.5},{3.5 , 4.5}};

    //the 1st argument is the address of the first row i.e
    //the first 1D array
    //the 2nd argument is the no of rows of your array
    //the 3rd argument is the no of columns of your array
    myFunc(a[0],2,2);

    //same way as myFunc
    printArray(a[0],2,2);

    return 0;
}

Đầu ra của bạn sẽ như sau ...

11.5  12.5
13.5  14.5

1
Lý do duy nhất tôi có thể đưa ra lý do tại sao một người sẽ xử lý mảng trong trường hợp này là bởi vì người ta thiếu kiến ​​thức về cách hoạt động của con trỏ mảng.
Lundin

3
biến i phải được nhân với các cột, không phải bởi các hàng trừ khi các cột và các hàng bằng nhau như trong trường hợp này
Andrey Chernukha

4

Dưới đây là một vectơ ma trận ví dụ

#include <iostream>
#include <vector>
using namespace std;

typedef vector< vector<int> > Matrix;

void print(Matrix& m)
{
   int M=m.size();
   int N=m[0].size();
   for(int i=0; i<M; i++) {
      for(int j=0; j<N; j++)
         cout << m[i][j] << " ";
      cout << endl;
   }
   cout << endl;
}


int main()
{
    Matrix m = { {1,2,3,4},
                 {5,6,7,8},
                 {9,1,2,3} };
    print(m);

    //To initialize a 3 x 4 matrix with 0:
    Matrix n( 3,vector<int>(4,0));
    print(n);
    return 0;
}

đầu ra:

1 2 3 4
5 6 7 8
9 1 2 3

0 0 0 0
0 0 0 0
0 0 0 0

2

Chúng ta có thể sử dụng một số cách để truyền một mảng 2D cho một hàm:

  • Sử dụng một con trỏ, chúng ta phải đánh máy mảng 2D.

    #include<bits/stdc++.h>
    using namespace std;
    
    
    void func(int *arr, int m, int n)
    {
        for (int i=0; i<m; i++)
        {
           for (int j=0; j<n; j++)
           {
              cout<<*((arr+i*n) + j)<<" ";
           }
           cout<<endl;
        }
    }
    
    int main()
    {
        int m = 3, n = 3;
        int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
        func((int *)arr, m, n);
        return 0;
    }
  • Sử dụng con trỏ kép Theo cách này, chúng tôi cũng đánh máy mảng 2d

    #include<bits/stdc++.h>
    using namespace std;

   void func(int **arr, int row, int col)
   {
      for (int i=0; i<row; i++)
      {
         for(int j=0 ; j<col; j++)
         {
           cout<<arr[i][j]<<" ";
         }
         printf("\n");
      }
   }

  int main()
  {
     int row, colum;
     cin>>row>>colum;
     int** arr = new int*[row];

     for(int i=0; i<row; i++)
     {
        arr[i] = new int[colum];
     }

     for(int i=0; i<row; i++)
     {
         for(int j=0; j<colum; j++)
         {
            cin>>arr[i][j];
         }
     }
     func(arr, row, colum);

     return 0;
   }

1

Một điều quan trọng để vượt qua các mảng đa chiều là:

  • First array dimension không cần phải được chỉ định.
  • Second(any any further)dimension phải được chỉ định.

1.Khi chỉ có chiều thứ hai có sẵn trên toàn cầu (dưới dạng macro hoặc là hằng số toàn cầu)

`const int N = 3;

`void print(int arr[][N], int m)
{
int i, j;
for (i = 0; i < m; i++)
  for (j = 0; j < N; j++)
    printf("%d ", arr[i][j]);
}`

int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr, 3);
return 0;
}`

2.Sử dụng một con trỏ : Trong phương thức này, chúng ta phải đánh máy mảng 2D khi truyền vào hàm.

`void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
  for (j = 0; j < n; j++)
    printf("%d ", *((arr+i*n) + j));
 }

`int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;

// We can also use "print(&arr[0][0], m, n);"
print((int *)arr, m, n);
return 0;
}`

0

Bạn có thể sử dụng tiện ích mẫu trong C ++ để làm điều này. Tôi đã làm một cái gì đó như thế này:

template<typename T, size_t col>
T process(T a[][col], size_t row) {
...
}

vấn đề với cách tiếp cận này là với mỗi giá trị col mà bạn cung cấp, một định nghĩa hàm mới được khởi tạo bằng cách sử dụng mẫu. vì thế,

int some_mat[3][3], another_mat[4,5];
process(some_mat, 3);
process(another_mat, 4);

khởi tạo khuôn mẫu hai lần để tạo ra 2 định nghĩa hàm (một trong đó col = 3 và một trong đó col = 5).


0

Nếu bạn muốn vượt qua int a[2][3]để void func(int** pp)bạn cần phải bước phụ trợ như sau.

int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;

func(pp);

Là cái đầu tiên [2]có thể được chỉ định ngầm, nó có thể được đơn giản hóa hơn nữa như.

int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;

func(pp);

0

Trong trường hợp bạn muốn truyền một mảng 2 chiều có kích thước động cho một hàm, sử dụng một số con trỏ có thể phù hợp với bạn.

void func1(int *arr, int n, int m){
    ...
    int i_j_the_element = arr[i * m + j];  // use the idiom of i * m + j for arr[i][j] 
    ...
}

void func2(){
    ...
    int arr[n][m];
    ...
    func1(&(arr[0][0]), n, m);
}

0

Bạn được phép bỏ qua kích thước ngoài cùng bên trái và do đó, bạn kết thúc với hai tùy chọn:

void f1(double a[][2][3]) { ... }

void f2(double (*a)[2][3]) { ... }

double a[1][2][3];

f1(a); // ok
f2(a); // ok 

Điều này giống với con trỏ:

// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double***’ 
// double ***p1 = a;

// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double (**)[3]’
// double (**p2)[3] = a;

double (*p3)[2][3] = a; // ok

// compilation error: array of pointers != pointer to array
// double *p4[2][3] = a;

double (*p5)[3] = a[0]; // ok

double *p6 = a[0][1]; // ok

Sự phân rã của mảng N chiều thành con trỏ đến mảng N-1 được cho phép theo tiêu chuẩn C ++ , vì bạn có thể mất kích thước ngoài cùng bên trái và vẫn có thể truy cập chính xác các yếu tố mảng với thông tin kích thước N-1.

Chi tiết tại đây

Mặc dù, mảng và con trỏ không giống nhau : một mảng có thể phân rã thành một con trỏ, nhưng một con trỏ không mang trạng thái về kích thước / cấu hình của dữ liệu mà nó trỏ tới.

A char **là một con trỏ tới một khối bộ nhớ chứa các con trỏ ký tự , chính chúng trỏ đến các khối bộ nhớ của các ký tự. A char [][]là một khối bộ nhớ duy nhất chứa các ký tự. Điều này có tác động đến cách trình biên dịch dịch mã và hiệu suất cuối cùng sẽ như thế nào.

Nguồn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.