2010-04-12 75 views
5

Tôi đã viết qsort này:con trỏ Void trong C++

void qsort(void *a[],int low,int high, int (*compare)(void*,void*)); 

Khi tôi gọi đây trên

char *strarr[5]; 

Nó nói chuyển đổi không hợp lệ từ char ** để làm mất hiệu lực **. Tại sao điều này là sai?

Đây là mã:

#include<cstdlib> 
#include<cstdio> 
#include<iostream> 

using namespace std; 

inline void strswap(void *a,void *b) { 
    char *t=*(char**)a; 
    *(char**)a=*(char**)b; 
    *(char**)b=t; 
} 

int strcompare(void *a, void *b) { 
    return strcmp(*(char**)a,*(char**)b); 
} 

void qsort1(void *a[],int low,int high, int (*compare)(void*,void*), void (*swap)(void*,void*)) { 
    if(low>=high) 
     return; 
    int q=low-1; 
    for(int i=low;i<=high-1;i++) 
     if((*compare)(&a[i],&a[high]) < 0) 
      swap(&a[i],&a[++q]); 
    swap(&a[high],&a[++q]); 
    qsort1(a,low,q-1,compare,swap); 
    qsort1(a,q+1,high,compare,swap); 
} 

int main() { 
    const int n=3; 
    //int a[n]={4,6,8,12,10,9,8,0,24,3}; 
    char *strarr[5]={"abcd","zvb","cax"}; 
    qsort1(strarr,0,n-1,strcompare,strswap); 
    for(int i=0;i<n;i++) 
     cout << strarr[i] << " "; 
    cout << endl; 
    return 0; 
} 
+0

tại sao bạn đã gắn thẻ tên này là C? –

+1

Ồ, khi nói "Tại sao điều này sai?" sau đó tôi có thể liệt kê * rất nhiều thứ *. – Puppy

+0

@DeadMG là chính xác. Tìm hiểu về 'std :: vector',' std :: string' và 'std :: sort'. Nếu bạn cần trợ giúp chuyển đổi mã của bạn thành hiện thực C++, hãy hỏi. –

Trả lời

12

Chuyển đổi ngầm từ bất kỳ loại con trỏ nào thành void * được cho phép, bởi vì void * được định nghĩa là loại con trỏ có đủ dải mà nó có thể biểu thị bất kỳ giá trị nào mà bất kỳ loại con trỏ nào khác có thể. (Về mặt kỹ thuật, chỉ có đối tượng khác loại con trỏ, loại trừ con trỏ đến hàm).

này không có nghĩa là void * có cùng kích thước hoặc đại diện như bất kỳ loại con trỏ khác, mặc dù: Chuyển đổi một con trỏ từ một loại con trỏ đến một void *không nhất thiết phải rời khỏi đại diện cơ bản không thay đổi. Chuyển đổi từ double * thành void * cũng giống như chuyển đổi từ double thành int - nó phải xảy ra ở chế độ xem đầy đủ của trình biên dịch, bạn không thể ẩn chuyển đổi đó sau lưng trình biên dịch.

Vì vậy, điều này có nghĩa rằng trong khi void * là một con trỏ generic, void **không một con trỏ-to-pointer generic. Đó là một con trỏ đến void * - một con trỏ void ** chỉ nên trỏ đến các đối tượng void * thực (trong khi chính bản thân nó có thể trỏ đến bất kỳ thứ gì).

Đây là lý do tại sao không có chuyển đổi tiềm ẩn giữa type **void ** - vì lý do tương tự không có chuyển đổi tiềm ẩn giữa double *int *.

Hiện tại, có một trường hợp đặc biệt: vì lý do lịch sử, char * được đảm bảo có cùng yêu cầu kích thước, biểu diễn và căn chỉnh là void *. Điều này có nghĩa là chuyển đổi giữa char ** (cụ thể) và void ** thực sự là OK, ngoại trừ quy tắc chung. Vì vậy, trong trường hợp cụ thể là, mã của bạn là chính xác nếu bạn thêm một dàn diễn viên vào void ** khi bạn vượt qua strarr đến qsort1().

Tuy nhiên, qsort1() của bạn chỉ được xác định để hoạt động chính xác trên các mảng void * hoặc char * (bao gồm unsigned char * v.v ...). Bạn không thể sử dụng nó để sắp xếp một mảng của double * con trỏ, ví dụ (mặc dù nó thực sự sẽ hoạt động trên hầu hết các môi trường phổ biến hiện nay).

10

Bất kỳ con trỏ có thể được ngầm chuyển đổi sang một con trỏ void. Nhưng tham số đầu tiên của bạn không phải là một con trỏ trống - đó là một mảng con trỏ trống và không có chuyển đổi tiềm ẩn nào đối với điều đó. Bạn có thể muốn khai báo chức năng của mình là:

void qsort(void *,int low,int high, int (*compare)(void*,void*)); 

nhưng thật khó để nói mà không nhìn thấy mã.