Giả sử bạn muốn sắp xếp một mảng của int
s bằng cách sử dụng qsort
.
int numbers[] = {10, 50, 35, 62, 22};
Trước tiên, bạn tạo một hàm có thể so sánh hai int
s.
int intCompare(void* p1, void* p2)
{
int n1 = *(int*)p1;
int n2 = *(int*)p2;
return (n1 < n2);
}
Sau đó, bạn có thể sử dụng:
qsort(numbers, 5, sizeof(int), intCompare);
Khi numbers
được chuyển cho qsort
, nó được phân rã đến một int*
và thông qua như void*
. Khi chúng ta cần trích xuất số từ một số void*
trong intCompare
, chúng ta cần phải đưa số đó đến int*
trước khi chúng ta dereference con trỏ và so sánh các giá trị.
Lấy tương tự với chuỗi, giả sử bạn muốn sắp xếp:
char* strings[] = { "abc", "xyz", "def" };
Các cuộc gọi đến qsort
sẽ là:
qsort(strings, 3, sizeof(char*), scmp);
Khi strings
được chuyển cho qsort
, nó được phân rã đến một char**
và được chuyển thành void*
. Các loại con trỏ cơ bản được chuyển đến scmp
bởi qsort
sẽ thuộc loại char**
, không phải là char*
. Do đó, việc sử dụng chính xác là:
int scmp(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
Phiên bản đầu tiên hoạt động do trùng hợp ngẫu nhiên trong một số trường hợp. Đây là một chương trình ví dụ cho thấy vài trường hợp nó không hoạt động trong khi phiên bản thứ hai luôn hoạt động.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// First version of scmp
int scmp1(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = (char *) p1;
v2 = (char *) p2;
return strcmp(v1,v2);
}
// Second version of scmp
int scmp2(const void *p1, const void * p2)
{
char *v1, *v2;
v1 = *(char **) p1;
v2 = *(char **) p2;
return strcmp(v1,v2);
}
void test1()
{
char* strings[] = { "abc", "xyz", "def" };
qsort(strings, 3, sizeof(char*), scmp1);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
printf("\n");
}
void test2()
{
char* strings[] = { "abc", "xyz", "def" };
qsort(strings, 3, sizeof(char*), scmp2);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
printf("\n");
}
void test3()
{
char** strings = malloc(3*sizeof(char*));
strings[0] = "abc";
strings[1] = "xyz";
strings[2] = "def";
qsort(strings, 3, sizeof(char*), scmp1);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
free(strings);
printf("\n");
}
void test4()
{
char** strings = malloc(3*sizeof(char*));
strings[0] = "abc";
strings[1] = "xyz";
strings[2] = "def";
qsort(strings, 3, sizeof(char*), scmp2);
for(int i = 0; i < 3; ++i)
{
printf("%s\n", strings[i]);
}
free(strings);
printf("\n");
}
int main()
{
// Does not work.
test1();
// Should work always.
test2();
// Does not work.
test3();
// Should work always.
test4();
}
Output (sử dụng gcc 4.8.4):
abc
xyz
def
abc
def
xyz
abc
xyz
def
abc
def
xyz
Phiên bản thứ hai có vẻ đúng với tôi.Rất khó để biết phiên bản đầu tiên hoạt động như thế nào mà không thấy phần còn lại của mã của bạn. –
làm thế nào để bạn gọi hàm? Nếu bạn gọi hàm giống như 'scmp (" hello "," hello ");' chỉ phiên bản đầu tiên sẽ hoạt động: http://ideone.com/P96Wmj – mch
Nó có thể hoạt động trong một số trường hợp nhưng nó sẽ không làm việc cho mọi trường hợp. Nếu ví dụ p1 trỏ tới chuỗi "abcdefgh" và p2 thành chuỗi khác "abcdefgh". Bây giờ các chuỗi là như nhau vì vậy cả hai đều được hiểu là cùng một địa chỉ (chúng ta hãy gọi nó là p). Sau đó strcmp sẽ so sánh chuỗi tại p với chuỗi tại p và vì cả hai tham số đều trỏ đến cùng một địa chỉ, nội dung theo định nghĩa giống nhau. –