2011-11-20 55 views
14
Activity solution[a][b]; 

... 

Activity **mother = solution; 

Tôi muốn chuyển đổi mảng đối tượng 2D thành con trỏ trỏ tới. Tôi có thể làm cái này như thế nào;chuyển đổi mảng 2D thành con trỏ thành con trỏ

Tôi đã tìm kiếm trên Google. tuy nhiên tôi chỉ tìm thấy một ví dụ về mảng thứ nguyên.

+0

[Hỏi đáp liên quan] (http://stackoverflow.com/questions/4810664/) – fredoverflow

Trả lời

13

Một chuyển đổi đơn giản sẽ không giúp bạn ở đây. Không có khả năng tương thích của bất kỳ loại nào giữa loại mảng 2D và kiểu con trỏ tới con trỏ. Chuyển đổi như vậy sẽ không có ý nghĩa.

Nếu bạn thực sự thực sự cần phải làm điều đó, bạn cần phải giới thiệu thêm một trung gian "chỉ số hàng" mảng, mà sẽ thu hẹp khoảng cách giữa ngữ nghĩa mảng 2D và ngữ nghĩa con trỏ-to-pointer

Activity solution[a][b]; 

Activity *solution_rows[a] = { solution[0], solution[1] /* and so on */ }; 

Activity **mother = solution_rows; 

Bây giờ truy cập mother[i][j] sẽ cấp cho bạn quyền truy cập vào solution[i][j].

+0

cảm ơn. nó giải quyết vấn đề của tôi –

0

Bạn không thể. Chúng về cơ bản là các loại khác nhau.

+0

Bạn có thể giải thích nó một cách chi tiết? –

+0

Nếu bạn cung cấp thêm chi tiết về những gì bạn muốn làm với 'mẹ', sau đó tôi có thể đưa ra một gợi ý trong câu trả lời của tôi. –

4

Tôi muốn chuyển đổi mảng mảng 2D của đối tượng thành con trỏ tới con trỏ. Tôi có thể làm cái này như thế nào?

Tại sao? Có phải vì giao diện mong đợi một con trỏ trỏ tới con trỏ không?

Nếu có, bạn sẽ cần tạo một mảng mới chứa các con trỏ đó.

Activity solution[a][b]; 

Activity* solutionPtrs[a]; 
for (int i = 0; i < a; ++i) 
    solutionPtrs[a] = solution[a]; 

Activity** mother = solutionPtrs; 

Tại sao bạn không thể truyền mảng 2D T tới T**? Vâng, bởi vì họ không có gì để làm với nhau!

Bạn có thể bỏ một T[a] đến T* vì bạn nhận được một con trỏ đến phần tử đầu tiên của mảng.

Bạn cũng có thể làm điều này với các mảng 2D, nhưng nếu bạn có T[a][b] thì nó phân rã thành (T[b])* vì mảng 2D không phải là một mảng con trỏ, đó là mảng mảng.

+0

cảm ơn. nó giải quyết vấn đề của tôi –

8

Lý do bạn có thể thực hiện việc này đối với mảng một chiều và không phải mảng hai chiều phải làm theo cách thức mà các phần tử mảng thực được lưu trữ trong bộ nhớ. Đối với mảng một chiều, tất cả các phần tử được lưu trữ liên tiếp, do đó biểu thức array[i] tương đương với biểu thức *(array + i). Như bạn có thể thấy, kích thước mảng là không cần thiết để thực hiện thao tác chỉ mục mảng. Tuy nhiên, đối với mảng hai chiều, các phần tử được lưu trữ theo thứ tự "hàng lớn", có nghĩa là tất cả các phần tử trong hàng zeroth được lưu trữ trước, theo sau là các phần tử trong hàng đầu tiên, tiếp theo là các phần tử trong hàng thứ hai , v.v. Do đó, biểu thức array[i][j] tương đương với *(array + (i * ROW_SIZE) + j), trong đó ROW_SIZE là số phần tử trong mỗi hàng. Do đó, kích thước hàng của mảng là cần thiết để thực hiện thao tác chỉ mục mảng và việc đúc biến mảng tới một con trỏ sẽ mất thông tin đó.

0

Không chắc chắn nếu bạn đang tìm kiếm một cái gì đó như thế này. Bạn nên cung cấp thêm chi tiết về những gì bạn muốn đạt được. Chúng về cơ bản là các loại khác nhau. Một giải pháp là dưới đây.

Đối với hồ sơ, nếu ai đó tìm thấy nó hữu ích:

// define matrix 
double A[3][3] = { 
    { 1, 2, 3}, 
    { 4, 5, 6}, 
    { 7, 8, 9} 
}; 

// allocate memory 
double ** A_ptr = (double **) malloc(sizeof (double *) * 3); 
for (int i = 0; i < 3; i++) 
    A_ptr[i] = (double *) malloc(sizeof (double) * 3); 

// copy matrix 
for (int i = 0; i < 3; i++) { 
    for (int j = 0; j < 3; j++) { 
     A_ptr[i][j] = A[i][j]; 
     printf(" %f ", A_ptr[i][j]); 
    } 
} 
3

Đây là ! Mọi thứ đều có thể! Nhưng đây là vì vậy nó đòi hỏi một mức độ hiểu biết.

Cuối cùng chúng ta hãy bắt đầu với một ví dụ đơn giản của mảng 2 1 chiều: char firstName[4] = { 'J', 'o', 'n', '\0' }char lastName[4] = { 'M', 'e', 'e', '\0' } Hãy xem xét một cách bố trí bộ nhớ có thể ở đây:

+------------+-------+ 
| Address | Value | 
+------------+-------+ 
| 0x| 0x4A | <- firstName[0] - 'J' 
| 0x76543211 | 0x6F | <- firstName[1] - 'o' 
| 0x76543212 | 0x6E | <- firstName[2] - 'n' 
| 0x76543213 | 0x00 | <- firstName[3] - '\0' 
+------------+-------+ 
| 0x76543214 | 0x4D | <- lastName[0] - 'M' 
| 0x76543215 | 0x65 | <- lastName[1] - 'e' 
| 0x76543216 | 0x65 | <- lastName[2] - 'e' 
| 0x76543217 | 0x00 | <- lastName[3] - '\0' 
+------------+-------+ 

Với cách bố trí bộ nhớ này nếu bạn đã làm cout << firstName << ' ' << lastName bạn 'd nhận được:

0x0x76543214

Những ar tia thực sự chỉ là một con trỏ đến yếu tố đầu tiên của chúng! Điều này minh họa Array Pointer Decay, mà bạn có thể đọc thêm về ở đây: http://en.cppreference.com/w/cpp/language/array#Array-to-pointer_decay

Trước khi chúng ta di chuyển trên có điều gì đó quan trọng ở đây cần lưu ý, char s mất chính xác 1-byte, vì thế địa chỉ của từng tiếp theo char trong mảng sẽ chỉ đơn giản là địa chỉ tiếp theo. Đó là đòn bẩy của Subscript Operator theo cách này: firstName[1] tương đương với *(firstName + 1). Điều này đúng với char s nhưng cũng đúng đối với bất kỳ loại nào khác chiếm hơn 1 byte. Chúng ta hãy xem ví dụ: short siArray = { 1, 2, 3, 4 }, một cách bố trí bộ nhớ có thể có của siArray sẽ trông như thế:

+------------+--------+ 
| Address | Value | 
+------------+--------+ 
| 0x76543218 | 0x0001 | <- siArray[0] - 1 
| 0x7654321A | 0x0002 | <- siArray[1] - 2 
| 0x7654321C | 0x0003 | <- siArray[2] - 3 
| 0x7654321E | 0x0004 | <- siArray[3] - 4 
+------------+--------+ 

Mặc dù cout << siArray << ' ' << &(siArray[1]) chí đầu ra:

0x76543218 0x7654321A

*(siArray + 1) sẽ vẫn chỉ số giống nhau phần tử của siArraysiArray[1]. Điều này là do khi thực hiện số học con trỏ xem xét loại địa chỉ đang hoạt động, do đó việc tăng thêm short* sẽ thực sự tăng địa chỉ theo số sizeof(short). Bạn có thể đọc thêm về số học con trỏ tại đây: http://en.cppreference.com/w/cpp/language/operator_arithmetic

Cuối cùng, hãy xem cách lưu trữ mảng 2 chiều. Đưa ra: char name[2][4] = { { 'J', 'o', 'n', '\0' }, { 'M', 'e', 'e', '\0' } } một cách bố trí bộ nhớ có thể sẽ là:

+------------+-------+ 
| Address | Value | 
+------------+-------+ 
| 0x76543220 | 0x4A | <- name[0][0] - 'J' 
| 0x76543221 | 0x6F | <- name[0][1] - 'o' 
| 0x76543222 | 0x6E | <- name[0][2] - 'n' 
| 0x76543223 | 0x00 | <- name[0][3] - '\0' 
| 0x76543224 | 0x4D | <- name[1][0] - 'M' 
| 0x76543225 | 0x65 | <- name[1][1] - 'e' 
| 0x76543226 | 0x65 | <- name[1][2] - 'e' 
| 0x76543227 | 0x00 | <- name[1][3] - '\0' 
+------------+-------+ 

Vì chúng ta biết một giá trị mảng 1 chiều thực sự chỉ là một con trỏ, chúng ta có thể nhìn thấy từ cách bố trí bộ nhớ này mà name[0]không phải là một con trỏ, nó chỉ là ký tự đầu tiên của mảng đầu tiên. Do đó namekhông chứa 2 con trỏ mảng 1 chiều, nhưng chứa nội dung của 2 mảng. (Ngẫu nhiên trên một máy 32-bit không lưu trữ các con trỏ tiết kiệm 8-byte bộ nhớ, mà là khá đáng kể cho một mảng 2-chiều 2-byte.) Vì vậy, cố gắng để điều trị name như là một char** sẽ cố gắng sử dụng các ký tự như một con trỏ.


Có hiểu điều này chúng tôi thực sự chỉ cần tránh sử dụng số học con trỏ để tìm giá trị dereference. Để làm được điều đó chúng tôi sẽ cần phải làm việc với một char* để thêm 1 thực sự là chỉ cần thêm 1. Vì vậy, ví dụ:

const short si2DArray[2][3] = { { 11, 12, 13 }, { 21, 22, 23 } }; 
const auto psi2DPointer = reinterpret_cast<const char*>(si2DArray); 

for(auto i = 0U; i < size(si2DArray); ++i) { 
    for(auto j = 0U; j < size(*si2DArray); ++j) { 
     cout << *reinterpret_cast<const short*>(psi2DPointer + i * sizeof(*si2DArray) + j * sizeof(**si2DArray)) << '\t'; 
    } 
    cout << endl; 
} 

Live Example

Lưu ý rằng trong ví dụ này mặc dù tôi tham khảo si2DArray nghĩ psi2DPointer tôi vẫn đang sử dụng thông tin từ si2DArray làm việc lập chỉ mục, cụ thể là:

  1. có bao nhiêu mảng đang trong chiều hướng chính: size(si2DArray)
  2. .210
  3. Có bao nhiêu yếu tố này trong chiều nhỏ: size(*si2DArray)
  4. kích thước trong bộ nhớ của kích thước nhỏ là gì: sizeof(**si2DArray)

Bạn do đó có thể thấy: sizeof(*si2DArray)

  • kiểu phần tử của mảng là gì rằng việc mất thông tin từ chuyển đổi từ một mảng sang con trỏ là đáng kể. Bạn có thể bị cám dỗ để bảo toàn kiểu phần tử, do đó cũng đơn giản hóa số học con trỏ. Đó là giá trị cần lưu ý rằng chỉ có một chuyển đổi để char* được coi là hành vi được xác định bởi reinterpret_cast: http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing

  • +0

    Cảm ơn rất nhiều Jonathan cho giải pháp của bạn. Bạn có biết chi phí được thực hiện bởi chuyển đổi này không? và ý bạn là gì bởi "chuyển đổi là đáng kể"? – khateeb

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