我剛剛開始學習 C。任何幫助表示贊賞!
我有一個指向結構的指標陣列,我想使用內置的qsort 函式根據指標指向的結構中的值對陣列進行排序。我正在嘗試使用官方檔案中演示的比較功能。
以下版本失敗:
int compare_nodes(const void* a, const void* b){
const struct ListNode * ptr1 = ((const struct ListNode *) a);
const struct ListNode * ptr2 = ((const struct ListNode *) b);
// const struct ListNode * ptr1 = *((const struct ListNode **) a);
// const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
此版本成功:
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
我不明白兩個版本之間的區別:
- 如果強制轉換只告訴編譯器如何解釋指標指向的地址,那么版本 1 中的問題是什么?告訴編譯器將指向 void 的指標解釋為指向 struct ListNode 的指標還不夠嗎?為什么我需要通過強制轉換添加一層間接層,然后通過取消參考洗掉一層?
- C 的值傳遞在這里有什么作用嗎?我自己想不出任何理由。
我找到了關于這個問題的以下資源。雖然他們似乎解釋了這個問題(尤其是資源 6),但我不明白他們:
在 C 中轉換指標的規則是什么?
C中指標的型別轉換
指標型別轉換和取消參考
在 C 中轉換指標的規則是什么?
C 演員的真正作用是什么?
https://cboard.cprogramming.com/c-programming/102056-casting-pointer-pointer.html
這是完整的代碼:
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
struct ListNode {
int val;
struct ListNode *next;
};
int calc_list_length(struct ListNode * head){
int target = 0;
struct ListNode * tmp = head;
while (tmp)
{
target ;
tmp = tmp -> next;
}
return target;
}
int compare_nodes(const void* a, const void* b){
// const struct ListNode * ptr1 = ((const struct ListNode *) a);
// const struct ListNode * ptr2 = ((const struct ListNode *) b);
const struct ListNode * ptr1 = *((const struct ListNode **) a);
const struct ListNode * ptr2 = *((const struct ListNode **) b);
int arg1 = ptr1 -> val;
int arg2 = ptr2 -> val;
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
struct ListNode* sortList(struct ListNode* head){
if(!head) return NULL;
int list_length = calc_list_length(head);
struct ListNode * tmp = head;
struct ListNode * arr[list_length];
for (int i = 0; i < list_length; i )
{
arr[i] = tmp;
tmp = tmp -> next;
}
for (int i = 0; i < list_length; i ) {
printf("%d ", arr[i] -> val);
}
printf("\n");
qsort(arr, list_length, sizeof(struct ListNode *), compare_nodes);
for (int i = 0; i < list_length; i ) {
printf("%d ", arr[i] -> val);
}
printf("\n");
}
int main(){
// [2,1,4,3]
struct ListNode node4 = {.val = 3, . next = NULL};
struct ListNode * ptr4 = &node4;
struct ListNode node3 = {.val = 4, .next = ptr4};
struct ListNode * ptr3 = &node3;
struct ListNode node2 = {.val = 1, .next = ptr3};
struct ListNode * ptr2 = &node2;
struct ListNode node1 = {.val = 2, .next = ptr2};
struct ListNode * ptr1 = &node1;
sortList(ptr1);
getchar();
return 0;
}
提前致謝。我希望你指出我正確的方向。
uj5u.com熱心網友回復:
使用指向運算子的qsort指標傳遞指向陣列元素的指標&。
例如,它可以&arr[0]作為&arr[1]比較函式的引數傳遞。
由于arr是一個指標陣列,其中每個元素都是一個指標,那么根據定義,指向一個元素的指標必須是指向指標的指標。
所以傳遞給你的compare_nodes結構的引數是指向結構的指標ListNode。
uj5u.com熱心網友回復:
函式 qsort 宣告如下
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
那就是函式處理型別的指標void *。const void *它將兩個指向底層陣列元素的型別的指標傳遞給比較函式。
你宣告了一個指標陣列
struct ListNode * arr[list_length];
它的型別元素ListNode *通過指向它們的指標通過參考傳遞給比較函式。
事實上,該函式傳遞給作為型別
ListNode **指標傳遞的型別的比較函式指標const void *。您可以通過以下方式想象
const void *p = &arr[i];
其中運算式&arr[i]的型別為ListNode **。
當然,該函式qsort實際上并不知道陣列元素的實際型別。它使用以下指標演算法
const void *p = ( char * )base i * size;
因此,在比較功能中,您需要進行“反向”轉換,例如
const struct ListNode * ptr1 = *((const struct ListNode **) a);
其中ptr1是原始陣列的一個元素,它通過指向它的指標通過參考傳遞給比較函式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/532310.html
