2013-04-02 42 views
9

Tôi có ma trận như vậy trong chương trình của tôi:C++ đúc tĩnh hai chiều mảng đôi tăng gấp đôi **

double m[3][4] = 
    { 
     {2, 4, 5, 7}, 
     {4, 5, 1, 12}, 
     {9, 12, 13, -4} 
    }; 

Và tôi muốn bỏ nó vào double** loại.

Tôi đã cố gắng đơn giản double** a = (double**)m;, nhưng nó không hoạt động (khi tôi cố gắng đọc bất kỳ giá trị, tôi nhận được "sự vi phạm truy cập vị trí đọc 0x00000000.", Có nghĩa là tôi đang cố gắng để đọc từ NULL địa chỉ.

tôi thấy gần như giải pháp làm việc:

double *b = &m[0][0]; 
double **c = &b; 

Nó hoạt động khi tôi đọc lĩnh vực c[0][any] Nhưng cùng NULL địa chỉ vấn đề đọc xảy ra, khi tôi cố gắng đọc giá trị từ lĩnh vực c[1][0]

.

Cách thích hợp để đúc mảng double m[3][4] của tôi là gì để nhập double**?

chỉnh sửa: Bạn nói điều đó là không thể. Vì vậy, tôi sẽ thay đổi một chút vấn đề. Làm thế nào tôi có thể vượt qua mảng hai chiều như một tham số cho một chức năng? Hàm của tôi có nguyên mẫu:

void calculate(double **matrix, int n); //where matrix size is always n by n+1 

Và nó hoạt động tốt với mảng được phân bổ động. Tôi nghi ngờ rằng cách duy nhất để làm cho nó hoạt động được phân bổ mảng động mới và sao chép mảng tĩnh ban đầu một yếu tố khác ...

+0

Đúc sẽ không thực hiện công việc này. Một 'double **' đòi hỏi một con trỏ tới một con trỏ tới một double, và đó không phải là những gì bạn có. Bạn có thể * có thể * nhận được bằng một 'double *' và rõ ràng truyền các kích thước mảng mặc dù. –

+1

Một mảng các mảng và một con trỏ tới một con trỏ không giống nhau. Bố cục trong bộ nhớ không khớp nên không thể sử dụng bố cục cho bộ nhớ khác. –

+1

Sử dụng kỹ thuật mà Vaughn Cato đề xuất. Nếu nó cần một 'double **', bạn cần phải cho nó một 'double **' và không phải là mảng hai chiều. –

Trả lời

9

Bạn không thể truyền mảng. Bạn sẽ phải tạo một cái gì đó như thế này:

double m[3][4] = 
    { 
     {2, 4, 5, 7}, 
     {4, 5, 1, 12}, 
     {9, 12, 13, -4} 
    }; 

double *marray[3] = {m[0],m[1],m[2]}; 
calculate(marray,3); 

Hoặc bạn có thể sử dụng một vòng lặp:

const size_t n = 3; 
double *marray[n]; 
for (size_t i=0; i!=n; ++i) { 
    marray[i] = m[i]; 
} 
calculate(marray,n); 
+0

Điều đó sẽ không hoạt động trong trường hợp của tôi. Mảng có thể có kích thước, ví dụ: 100x100. Và tôi sẽ không viết '{m [0], m [1], m [2], ..., m [99]};' trong mã của tôi :) –

+1

@gogowitczak: Trong trường hợp đó, bạn có thể sử dụng một vòng lặp (câu trả lời được cập nhật). –

+0

Nó không phải là đơn giản. Tôi cho rằng 'mảng' có thể có các kích cỡ khác nhau mà không được biết tại thời gian biên dịch, nghĩa là' n' không phải là một hằng số thời gian biên dịch. Do đó 'marray' phải được phân bổ động. Mà có thể là tốt nhưng nếu bạn muốn tránh phân bổ động sử dụng một mẫu như tôi giải thích trong câu trả lời của tôi. –

14

Bạn không thể.

Ký hiệu double** đề cập đến một mảng con trỏ. Bạn không có một mảng con trỏ, bạn có một mảng các mảng đôi.

0

Bạn có thể vượt qua một mảng 2ngày như một tham số chức năng:

void calculate(double matrix[][y], int n);

0

Cho đến khi các mảng có độ dài thay đổi nằm trong tiêu chuẩn C++, các lựa chọn của bạn bao gồm:

  • Nếu trình biên dịch của bạn hỗ trợ các mảng có độ dài biến đổi làm phần mở rộng, bạn có thể chuyển chúng với khai báo hàm như void foo(std::size_t n, double a[][n+1]). Lưu ý rằng trình biên dịch có thể yêu cầu n được chuyển trước khi khai báo tham số sử dụng n hoặc yêu cầu một số cú pháp đặc biệt.
  • Bạn có thể vượt qua một double * và làm chỉ số số học bằng tay trong các chức năng: void foo(std::size_t n, double *a) { … a[row*(n+1) + column] … }
  • Bạn có thể tạo ra một lớp các dụng cụ mảng chiều dài thay đổi bằng cách làm như số học chỉ mục trong chức năng accessor của nó.
  • Bạn có thể cấp không gian cho n con trỏ đến double, điền vào các con trỏ đó với con trỏ tới từng hàng của mảng và chuyển địa chỉ của không gian.
1

Nếu bạn luôn sử dụng mảng (không có con trỏ) để khởi tạo và bạn có thể tránh các công cụ con trỏ trong hàm tính toán của mình, bạn có thể xem xét tùy chọn sau, sử dụng khấu trừ kích thước theo mẫu.

template<int m, int n> 
void doubleFunc(double (&mat)[m][n]) 
{ 
    for (auto i = 0; i < m; i++) 
    { 
     for (auto j = 0; j < n; j++) 
     { 
      std::cout << mat[i][j] << std::endl; 
     } 
    } 
} 

Nó hoạt động trong quá trình kiểm tra nhanh.

double m[3][4] = 
{ 
    {2, 4, 5, 7}, 
    {4, 5, 1, 12}, 
    {9, 12, 13, -4} 
}; 

doubleFunc(m); 
7

Khi bạn viết

double m[3][4] 
    { 
     {2, 4, 5, 7}, 
     {4, 5, 1, 12}, 
     {9, 12, 13, -4} 
    }; 

Trình biên dịch thực sự tạo ra một loạt các đôi như thể bạn đã viết

double _m[] = {2, 4, 5, 7, 4, 5, 1, 12, 9, 12, 13, -4}; 

Tuy nhiên, nhờ vào C/C loại hệ thống ++, trình biên dịch nhớ rằng m của loại là double [3][4]. Đặc biệt nó nhớ kích thước 3 và 4.

Khi bạn viết

m[i][j] 

trình biên dịch thay thế nó bằng

_m[i * 4 + j]; 

(Các 4 xuất phát từ kích thước thứ hai trong double [3][4].) Ví dụ , m[1][2] == 1_m[1 * 4 + 2] == _m[6] == 1.

Như những người khác đã nói, double** là loại khác không mang theo kích thước . Để xem xét double** a làm ma trận 3 x 4, a[0], a[1]a[2] phải là con trỏ đến double (nghĩa là, double*) trỏ đến thành phần đầu tiên của hàng tương ứng . Bạn có thể đạt được điều này với

double* rows[] = { &m[0][0], &m[1][0], &m[2][0] }; 
double** a = &rows[0]; 

Một dàn diễn viên đơn giản không tạo biến số rows ở trên. Hãy để tôi trình bày thay thế (nhưng tương đương) cách khác để xác định rows

double* rows[] = { &m[0][0], &m[0][0] + 4, &m[0][0] + 2 * 4}; 
double* rows[] = { &_m[0], &_m[4], &_m[2 * 4]}; 

Như bạn có thể thấy, chỉ có kích thước thứ hai (tức 4) là cần thiết. Nói chung, đối với mảng đa chiều, tất cả các kích thước nhưng yêu cầu đầu tiên là bắt buộc. Đối với lý do này một mảng 1 chiều

double x[4] = { 1, 2, 3, 4 }; 

có thể được ngầm chuyển đổi sang một double*

double* y = x; 

Sử dụng thực tế này, chúng ta cũng có thể viết

double* rows[] = { _m, _m + 4, _m + 2 * 4}; 

Thật vậy, _m được chuyển thành a double* trỏ đến m[0].Sau đó, trong _m + 4, _m được chuyển thành double* trỏ đến m[0] và tới con trỏ này , nó được thêm 4. Do đó, _m + 4 là một con trỏ thứ tư tăng gấp đôi sau _m[0], là _m[4] v.v.

Cho đến nay tôi đã giải thích lý do tại sao bạn không thể đúc double [3][4] (hoặc bất kỳ kích thước nào khác) vào double**. Bây giờ, tôi cho thấy, trong trường hợp cụ thể của bạn, cách tính toán có thể được xác định.

template <int N> 
void calculate(double (&m)[N][N+1]) { 
    // use m as a double[N][N+1] 
} 

Bạn gọi

calculate(m); 

và trình biên dịch sẽ suy ra kích thước N cho bạn. Nói chung (ví dụ: khi thứ nguyên thứ hai không phải là N + 1), bạn có thể viết

template <int N, int M> 
void calculate(double (&m)[N][M]) { 
    // use m as a double[N][M] 
} 
Các vấn đề liên quan