2009-10-18 27 views
12

tôi có một chương trình mà trông giống như sau:Chuyển đổi mảng đa chiều đối với con trỏ trong C++

double[4][4] startMatrix; 
double[4][4] inverseMatrix; 
initialize(startMatrix) //this puts the information I want in startMatrix 

bây giờ tôi muốn để tính toán nghịch đảo của startMatrix và đặt nó vào inverseMatrix. Tôi có một chức năng thư viện cho mục đích này có prototype như sau:

void MatrixInversion(double** A, int order, double** B) 

mà có nghịch đảo của A và đặt nó trong B. Vấn đề là tôi cần phải biết làm thế nào để chuyển đổi kép [4] [ 4] thành một đôi ** để cung cấp cho hàm. Tôi đã thử chỉ làm điều đó "cách rõ ràng":

MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix)) 

nhưng điều đó dường như không hoạt động. Đó có phải là cách thực sự để làm điều đó không?

+0

& startMatrix, 4 & nghịch đảoMatrix –

+1

Tại sao bạn không tạo một lớp ma trận, thay vì làm theo cách C? (Truyền các đối tượng vào các hàm, thay vì sau đó gọi các phương thức trên các đối tượng) – GManNickG

+2

@GMan: Vì OP cho biết hàm này là "một hàm thư viện", nên hầu như không có quyền tự do thay đổi giao diện. Lớp học hoặc không có lớp học, tại một số điểm, anh ta sẽ phải có được 'double **' thích hợp để chuyển sang hàm. – AnT

Trả lời

17

Không, không có cách nào để làm cụ thể điều đó. Mảng double[4][4] không thể chuyển đổi thành con trỏ double **. Đây là hai cách thay thế, không tương thích để triển khai mảng 2D. Một cái gì đó cần phải được thay đổi: hoặc là giao diện của chức năng, hoặc cấu trúc của mảng được truyền như một đối số.

Cách đơn giản nhất để làm sau này, tức là để làm cho double[4][4] mảng hiện tại của bạn phù hợp với chức năng, là tạo ra tạm thời "chỉ số" mảng kiểu double *[4] trỏ đến sự khởi đầu của mỗi hàng trong mỗi ma trận

double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] }; 
double *inverseRows[4] = { /* same thing here */ }; 

và vượt qua những "chỉ số" mảng thay vì

MatrixInversion(startRows, 4, inverseRows); 

Khi chức năng làm việc kết thúc, bạn có thể quên đi những startRowsinverseRows mảng, vì kết quả sẽ là pl được nhập vào mảng inverseMatrix gốc của bạn một cách chính xác.

1

Mảng hai chiều không phải là con trỏ trỏ đến con trỏ hoặc tương tự. Loại chính xác cho bạn startMatrix là double (*)[4]. Đối với chức năng của bạn, chữ ký phải như sau:

MatrixInversion(double (*A)[4], int order, double (*B)[4]); 
+1

Hàm này dường như hoạt động với các ma trận vuông có kích thước bất kỳ (thứ tự). Hạn chế nó đến ma trận 4x4 chỉ là khó chấp nhận được. Ngoài ra, bây giờ không có điểm nào để vượt qua 'trật tự'. – AnT

+0

@AndreyT, tôi chỉ cho anh ta biết cách thực hiện. Nếu tôi muốn nói chung, tôi có thể chỉ cho anh ta cách để có một lớp đại diện cho một ma trận. – leiz

+0

Trong ma trận * vuông *, số lượng hàng giống với số cột. Bạn đã mã hóa số cột của bạn là 4. Bây giờ không có điểm nào để vượt qua số đếm hàng nữa - nó cũng phải là 4 và chỉ 4. – AnT

-1

Vấn đề là mảng hai chiều không giống như một mảng con trỏ. Mảng hai chiều lưu trữ các phần tử một hàng sau một khác — vì vậy, khi bạn truyền một mảng xung quanh, chỉ có một con trỏ tới điểm bắt đầu được đưa ra. Chức năng tiếp nhận có thể tìm ra cách tìm bất kỳ phần tử nào của mảng, nhưng chỉ nếu nó biết chiều dài của mỗi hàng.

Vì vậy, chức năng nhận của bạn phải được khai báo là void MatrixInversion(double A[4][], int order, double B[4][]).

+1

Nếu bạn biết kích thước của mảng và bạn biết nó được điền vào như thế nào, bạn có thể chuyển nó thành & A, nhưng bạn có rất nhiều điều bạn cần biết trước, nhưng có thể làm được. –

+0

Đây không phải là tuyên bố chính xác. Chỉ kích thước đầu tiên có thể được bỏ qua trong khai báo tham số mảng. Ngoài ra, việc sửa kích thước của ma trận sẽ làm mất khả năng felxibility của hàm (nghĩa là khả năng xử lý ma trận của bất kỳ kích thước nào). – AnT

+0

@James Black: Chính xác. Nếu chúng ta định sửa kích thước của ma trận vuông thì cách thích hợp để khai báo tham số sẽ là 'double (& A) [4] [4]', không phải 'double A [] [4]'. Ít nhất nó sẽ bảo toàn kiểu mảng đầy đủ, thay vì phân rã nó thành 'double (*) [4]'. – AnT

2

Vì bạn đang sử dụng C++, cách thích hợp để làm điều gì đó như thế này sẽ là với một lớp tùy chỉnh và một số mẫu. Ví dụ sau là khá thô, nhưng nó được điểm cơ bản trên.

#include <iostream> 

using namespace std; 

template <int matrix_size> 
class SquareMatrix 
{ 
    public: 
     int size(void) { return matrix_size; } 
     double array[matrix_size][matrix_size]; 
     void copyInverse(const SquareMatrix<matrix_size> & src); 
     void print(void); 
}; 

template <int matrix_size> 
void SquareMatrix<matrix_size>::copyInverse(const SquareMatrix<matrix_size> & src) 
{ 
    int inv_x; 
    int inv_y; 

    for (int x = 0; x < matrix_size; x++) 
    { 
     inv_x = matrix_size - 1 - x; 
     for (int y = 0; y < matrix_size; y++) 
     { 
      inv_y = matrix_size - 1 - y; 
      array[x][y] = src.array[inv_x][inv_y]; 
     } 
    } 
} 

template <int matrix_size> 
void SquareMatrix<matrix_size>::print(void) 
{ 
    for (int y = 0; y < 4; y++) 
    { 
     for (int x = 0; x < 4; x++) 
     { 
      cout << array[x][y] << " "; 
     } 
     cout << endl; 
    } 
} 

template <int matrix_size> 
void Initialize(SquareMatrix<matrix_size> & matrix); 

int main(int argc, char * argList[]) 
{ 
    SquareMatrix<4> startMatrix; 
    SquareMatrix<4> inverseMatrix; 

    Initialize(startMatrix); 

    inverseMatrix.copyInverse(startMatrix); 

    cout << "Start:" << endl; 
    startMatrix.print(); 

    cout << "Inverse:" << endl; 
    inverseMatrix.print(); 

    return 0; 
} 

template <int matrix_size> 
void Initialize(SquareMatrix<matrix_size> & matrix) 
{ 
    for (int x = 0; x < matrix_size; x++) 
    { 
     for (int y = 0; y < matrix_size; y++) 
     { 
      matrix.array[x][y] = (x+1)*10+(y+1); 
     } 
    } 
} 
+0

Tôi thích ý tưởng của bạn, cách chính xác của C++. một ví dụ tốt bất kể công việc hay không. – Test

+0

Cũng tốt để có một mẫu T, đó là những gì các yếu tố sẽ được. Và có thể làm cho kích thước unsigned, kể từ khi kích thước tiêu cực không có ý nghĩa. – GManNickG

+0

Tuy nhiên, thực hiện một hoạt động tương đối nặng (nó nghịch đảo, BTW, không transpose) như là một chức năng mẫu parametrized bởi kích thước ma trận có thể dẫn đến mã bloat, vì mã sẽ được tái instantiated cho mỗi kích thước cụ thể. Kỹ thuật xử lý thích hợp với vấn đề này là thực hiện phần lớn chức năng bằng một hàm được parametrized với kích thước thời gian chạy (như trong câu hỏi ban đầu) và sau đó xây dựng một mẫu "mỏng" ở trên cùng của hàm đó. Nhưng điều đó đưa chúng ta trở lại vấn đề ban đầu. – AnT

-2

bởi mã hóa tốt đẹp nếu C++:

struct matrix { 
    double m[4][4]; 
}; 

matrix startMatrix; 
matrix inverseMatrix; 

nên giao diện sẽ

void MatrixInversion(matrix &A, int order, matrix &B); 

và sử dụng nó

MatrixInversion(startMatrix, 4, inverseMatrix); 

Lợi ích

  1. giao diện rất đơn giản và rõ ràng.
  2. khi cần sửa đổi "m" ma trận trong nội bộ, bạn không cần cập nhật giao diện.

Hoặc cách này

struct matrix { 
    void Inversion(matrix &inv, int order) {...} 
protected: 
    double m[4][4]; 
}; 

matrix startMatrix; 
matrix inverseMatrix; 
... 

Một cách xấu xí trong c

void MatrixInversion(void *A, int order, void *B); 
MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix); 

EDIT: Mã tham chiếu cho MatrixInversion mà sẽ không sụp đổ:

void MatrixInversion(void *A, int order, void *B) 
{ 
    double _a[4][4]; 
    double _b[4][4]; 

    memcpy(_a, A, sizeof _a); 
    memcpy(_b, B, sizeof _b); 
    // processing data here 

    // copy back after done 
    memcpy(B, _b, sizeof _b); 
} 
+0

Lỗi thiết kế giống như trong một số phản hồi khác ... Bạn đã mã hóa kích thước ma trận cố định trong loại ma trận của mình. Bạn sẽ làm gì nếu bạn cần ma trận 5x5? 6x6? Và điểm truyền 4 cho hàm là gì, khi nào 4 đã được mã hóa thành loại ma trận? – AnT

+0

"Cách xấu xí trong C" của bạn sẽ chỉ đơn giản là phá vỡ chương trình. OP đã thử nó, nếu bạn nhận thấy, và nó không hoạt động (vì lý do rõ ràng). – AnT

+0

quy tắc tái xuất: cải thiện thiết kế khi cần thiết. xem phần "Lợi ích". "4" là một ví dụ cụ thể, có nghĩa là một số nguyên và giá trị của nó là 4. – Test

4

Vì lý do cho rằng mảng hai chiều (một khối bộ nhớ liền kề) và một mảng các con trỏ (không tiếp giáp) là những thứ rất khác nhau, bạn không thể truyền một mảng hai chiều đến một hàm làm việc với con trỏ tới con trỏ.

Một điều bạn có thể làm: mẫu. Đặt kích thước của thứ nguyên thứ hai thành thông số mẫu.

#include <iostream> 

template <unsigned N> 
void print(double a[][N], unsigned order) 
{ 
    for (unsigned y = 0; y < order; ++y) { 
     for (unsigned x = 0; x < N; ++x) { 
      std::cout << a[y][x] << ' '; 
     } 
     std::cout << '\n'; 
    } 
} 

int main() 
{ 
    double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}}; 
    print(arr, 3); 
} 

khác, một chút vụng về cách có thể để làm cho chức năng chấp nhận một con trỏ đến một mảng đơn chiều, và cả chiều rộng và chiều cao được cho là đối số, và tính toán các chỉ số thành một đại diện hai chiều chính mình.

#include <iostream> 

void print(double *a, unsigned height, unsigned width) 
{ 
    for (unsigned y = 0; y < height; ++y) { 
     for (unsigned x = 0; x < width; ++x) { 
      std::cout << a[y * width + x] << ' '; 
     } 
     std::cout << '\n'; 
    } 
} 

int main() 
{ 
    double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}}; 
    print(&arr[0][0], 3, 3); 
} 

Tự nhiên, ma trận là thứ xứng đáng với một lớp riêng (nhưng ở trên vẫn có thể có liên quan, nếu bạn cần viết chức năng trợ giúp).

0

Có một giải pháp bằng cách sử dụng con trỏ đến điểm bởi bobobobo

William Sherif (bobobobo) sử dụng phiên bản C và tôi chỉ muốn hiển thị C++ phiên bản của câu trả lời bobobobo của.

int numRows = 16 ; 
int numCols = 5 ; 
int **a ; 

a = new int*[ numRows* sizeof(int*) ]; 
for(int row = 0 ; row < numRows ; row++) 
{ 
    a[row] = new int[ numCols*sizeof(int) ]; 
} 

Phần còn lại của mã giống với bobobobo.

Các vấn đề liên quan