2011-11-21 36 views
6

Tôi muốn gán mảng được phân bổ tĩnh, đa chiều cho một biến tạm thời. Hãy xem xét ví dụ sau:Làm thế nào để gán một mảng đa chiều cho một biến tạm thời?

void foo(int b[3][2]) 
{ 
    b[1][1] = 1; // no segmentation fault 
} 

int main() 
{ 
    int a[3][2] = {{1, 2}, {11, 12}, {21, 22}}; 

    foo(a); 

    int** c; 
    c = (int**)&a; 
    c[1][1] = 1; // segmentation fault on execution 

    int* d[3]; 
    d[0] = (int*)&(a[0]); 
    d[1] = (int*)&(a[1]); 
    d[2] = (int*)&(a[2]); 
    d[1][1] = 1; // no segmentation fault 

    return 0; 
} 

Về cơ bản tôi muốn làm những gì trình biên dịch thực hiện với tham số b của foo(). Nhưng giải pháp làm việc duy nhất tôi có thể đưa ra là d. Có cách nào ít phức tạp hơn không?

+0

Thật kỳ lạ có bao nhiêu người nghĩ rằng một mảng 2D bằng cách nào đó trực tiếp chuyển sang con trỏ tới con trỏ. – tenfour

Trả lời

11

cdecl (man page) là bạn của bạn:

cdecl> explain int b[3][2] 
declare b as array 3 of array 2 of int 
cdecl> declare b as pointer to array 2 of int 
int (*b)[2] 

Vì vậy, hãy thử này:

void foo(int b[3][2]) 
{ 
    b[1][1] = 1; // no segmentation fault 
} 

int main() 
{ 
    int a[3][2] = {{1, 2}, {11, 12}, {21, 22}}; 

    foo(a); 

    int (*b)[2] = a; 

    b[1][1] = 1; 

    return 0; 
} 
+0

huh - đó là mới. cdecl ở đâu? – sehe

+0

OMG _cdecl_: D: D: D Tôi chưa bao giờ thấy điều này: D Có phiên bản trực tuyến: @sehe - http://cdecl.org/ –

+1

+1, cảm ơn cdecl ;-) –

9

int[3][2]int** nhiều loại không tương thích. Bạn không thể đúc một cái khác.

Hãy thử điều này:

int (*c)[2]; 
c = a; //no need to cast 
c[1][1] = 1; //ok 

Hoặc bạn có thể làm điều này (khai cũng như khởi tạo):

int (*c)[2] = a; //no need to cast 
c[1][1] = 1; //ok 

Thumb của quy tắc:

  • Đừng dùng c-style cast trong C++. Sử dụng C++ - dàn diễn viên. Đã bạn sử dụng C++ - phong cách diễn viên, trình biên dịch sẽ nói với bạn những vấn đề nhiều trước (ideone) (không cần phải chạy mã để xem vấn đề):

    prog.cpp:5: error: invalid static_cast from type ‘int (*)[3][2]’ to type ‘int**’ 
    

    Nhưng C-style cast biên dịch nó tốt (ideone), như bạn đã biết.

  • Và bất cứ khi nào bạn sử dụng tính năng truyền, ngay cả khi tạo kiểu C++, nghi ngờ đầu tiên của bạn sẽ là tự diễn nếu chương trình không hoạt động như mong đợi.

+1

Bạn có lỗi đánh máy: –

+1

@KirilKirov: Đã sửa lỗi. Cảm ơn. – Nawaz

2

Nếu bạn đang sử dụng một trình biên dịch khá hiện đại hỗ trợ đủ các bộ phận của tiêu chuẩn C++ 11, bạn có thể sử dụng auto:

int a[3][2] = ...; 
auto &b = a; 
b[1][1] = 1; // a[1][1] will be set 

Tất nhiên, cả hai ab phải được xác định trong cùng một phạm vi cho nó hoạt động. Bạn không thể có một tham số auto trong một chức năng ví dụ (đó là những gì các mẫu dành cho.)

5

Như bạn có thể nhận thức bây giờ, từ câu trả lời khác, loại a là không thực sự tương đương với int** - nó jsut phân rã cho điều đó (khi trả về/được chuyển theo giá trị).

int (*b)[2] = a; // would solve that 

Có một C++ cách hơn:

typedef std::array<std::array<int, 2>, 3> M23; 

void foo(M23& b) 
{ 
    b[1][1] = 1; 
} 

int main() 
{ 
    M23 a = {{1, 2}, {11, 12}, {21, 22}}; 

    foo(a); 

    M23 d = a; 
    d[1][1] = 1; 
} 
+1

+1 Mọi người đều thích 'std :: array' :-) –

+1

@sehe: Điều này là tốt, nhưng bạn cũng nên trả lời câu hỏi và giải thích vấn đề với mã của OP. Khi bạn đã giải thích điều đó, bạn có thể đề xuất giải pháp thay thế tốt hơn. – Nawaz

1

Xin chớ từ bỏ một cách rõ ràng, vì vậy hãy thử viết

c = &a; 

Sau đó trình biên dịch GCC (sử dụng gcc -Wall -g bidim.c -o bidim để biên dịch) mang đến cho bạn cảnh báo chính xác:

bidim.c:13:7: warning: assignment from incompatible pointer type [enabled by default] 

Và sau đó bạn sẽ nhận ra rằng một ma trận 2D không được thực hiện như một mảng các con trỏ tới các mảng 1D.

0

Điều đầu tiên mà đi vào tâm trí của tôi đang sử dụng một typedef và tài liệu tham khảo như

typedef int thing_t[3][2]; 
thing_t& e = a; 
e[1][1] = 1; 

Với con trỏ

int (*f)[2] = a; 
f[1][1] = 1; 

Một khả năng khác là để đóng gói nó trong struct.

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