2016-01-26 13 views
5

Tôi nhận được thông báo sau: incompatible pointer types 'void**' and 'int* [2]'.void ** pointer and void * [] làm tham số chức năng

Khi tôi cố gắng biên dịch đoạn mã sau:

#include <stdlib.h> 

void func1(void *arr[]) { } 

int main() { 
    int *arr[2]; 
    for (int i = 0; i < 5; i++) { 
     arr[i] = (int*)malloc(sizeof(int)); 
     *(arr[i]) = 5; 
    } 
    func1(arr); 
} 

Bây giờ, nó hoạt động khi tôi đúc arr với (void**), và tôi không thể tìm thấy một lý do cho điều đó. Hơn nữa tôi thấy rằng tôi cũng cần phải đúc trong đoạn mã sau:

#include <stdlib.h> 

void func1(void **arr) { } 

int main() { 
    int **arr; 
    int i[] = { 1, 2 }; 
    int j[] = { 3, 4 }; 
    *arr = i; 
    *(arr+1) = j; 
    func1(arr); //Doesn't compile unless I use (void*) or (void**) casting 
} 

Tôi biết rằng nếu tham số của hàm là một con trỏ để void chúng ta có thể vượt qua nó bất cứ điều gì con trỏ chúng ta muốn mà không đúc bởi vì tất cả con trỏ là của cùng kích thước thì tại sao tôi không thể chuyển con trỏ tới con trỏ theo cùng một cách?

+4

Ý của bạn là 'int * arr [5]; '? –

+4

Vì con trỏ tới con trỏ không phải là con trỏ tới 'void'. Chỉ một con trỏ tới 'void' được đảm bảo tương thích với các con trỏ khác. –

+0

Nếu con trỏ là mảng, chúng sẽ không được gọi là "con trỏ". – Olaf

Trả lời

2

Tất cả các loại con trỏ đối tượng, bao gồm int *, chắc chắn sẽ rất có thể đổi lẩn nhau được với void *, nhưng họ không hoán đổi cho nhau. Các đại diện của loại int * không phải giống như đại diện của loại void * (mặc dù trong thực tế, nó hầu như luôn luôn là), vì vậy không có chuyển đổi tự động từ một con trỏ đến int * (tức là int **) đến một con trỏ đến void * (tức là void **). Nó không phải là an toàn để giả định rằng một điều được chỉ định của một loại có thể được giải thích một cách chính xác như là một điều của loại được chỉ định khác.

Note, bằng cách này, rằng đây:

nếu tham số của hàm là một con trỏ để làm mất hiệu lực chúng ta có thể vượt qua nó bất cứ điều gì con trỏ chúng ta muốn mà không đúc bởi vì tất cả gợi ý là có cùng kích thước

là một đặc điểm không chính xác. Các con trỏ là không phải là bắt buộc cho tất cả cùng kích thước. Chỉ yêu cầu mỗi con trỏ đối tượng có thể được chuyển đổi thành loại void * và ngược lại và kết quả của chuyển đổi chuyến đi khứ hồi bằng với con trỏ ban đầu.

Làm lấy nhận xét của @ Lundin về tim: mảng không phải là con trỏ. Tuy nhiên, các giá trị của loại mảng làm phân rã thành con trỏ trong hầu hết các trường hợp, kể cả khi chúng xuất hiện dưới dạng đối số hàm hoặc làm toán hạng bên phải của toán tử gán.

4

Có một số vấn đề với đoạn mã thứ hai của bạn:

void func1(void** arr) { } 
int main() { 
    int** arr; 
    int i[] = {1,2}; 
    int j[] = {3,4}; 
    *arr = i; 
    *(arr+1) = j; 
    func1(arr); //Doesn't compile unless I use (void*) or (void**) casting 
} 

Bạn không bao giờ khởi arr để trỏ đến một con trỏ hoặc một mảng các con trỏ để int. Nó là uninitialized, vì vậy giá trị của nó có thể là bất cứ điều gì. Khi bạn đặt *arr thành i, bạn sẽ gọi hành vi không xác định.

Hơn nữa, int **void ** không phải là loại có khả năng tương thích, bạn không thể chuyển đổi một cách khác một cách ngầm định. Lý do cho điều này là trên một số hệ thống hiếm, int *void * có thể có một đại diện khác.Việc đưa con trỏ đến int * làm con trỏ đến void * sẽ không chính xác khi truyền con trỏ đến float làm con trỏ đến double. Trên các hệ thống có biểu diễn giống nhau, bạn chỉ có thể viết diễn viên rõ ràng.

Đây là một phiên bản sửa chữa:

#include <stdlib.h> 

void func1(void **arr) { } 

int main(void) { 
    int *int_pointer_array[2]; 
    int **arr = &int_pointer_array; 
    int i[] = { 1, 2 }; 
    int j[] = { 3, 4 }; 
    *arr = i;  /* this line modifies int_pointer_array[0] */ 
    *(arr+1) = j; /* this line modifies int_pointer_array[1] */ 
    func1((void **)arr); 
    return 0; 
} 
+0

"Phiên bản đã sửa" vẫn gây ra hành vi không xác định ngay cả khi các loại con trỏ có cùng kích thước và biểu diễn. Nó cũng vi phạm quy tắc bí danh nghiêm ngặt ('int *' được đặt tên là 'void *') –

+0

@MM: nó có, nhưng trong các hàm riêng biệt, không gây ra vấn đề nếu biểu diễn 'int *' và 'void *' giống nhau. – chqrlie

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