我們都給出了任務和鏈表的結構:鏈表 - 單或雙指針頭
typedef struct dlistint_s
{
int n;
struct dlistint_s *prev;
struct dlistint_s *next;
} dlistint_t;
並與原型如下功能:
dlistint_t *add_dnodeint(dlistint_t **head, const int n);
什麼優點以及爲什麼在創建函數時會使用雙指針指向頭部?
我們都給出了任務和鏈表的結構:鏈表 - 單或雙指針頭
typedef struct dlistint_s
{
int n;
struct dlistint_s *prev;
struct dlistint_s *next;
} dlistint_t;
並與原型如下功能:
dlistint_t *add_dnodeint(dlistint_t **head, const int n);
什麼優點以及爲什麼在創建函數時會使用雙指針指向頭部?
將指針傳遞到指針head
的原因是指針head
的任何修改都會在調用者函數中看到,並且您不必從函數返回頭部。
例如,考慮這個簡單的節點:
struct Node{
int data;
struct Node *next;
};
的一種功能節點在前面
struct Node *add_node (struct Node *list, int n){
struct Node *new_node = malloc(sizeof(struct Node));
if(new_node == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
new_node->data = n;
new_node->next = list;
return new_node;
}
添加到列表中。如果我們需要分配new_node
到list
,而不是返回的那麼我們需要修改上面的函數,並刪除return語句併發出聲明
list = new_node;
但是,,這將無法正常工作!
這是因爲在C中,像所有參數一樣,指針是按值傳遞的。 這意味着list
包含傳遞給add_node
函數的指針值的副本,而不是傳遞給此函數本身的指針。
這就是我們需要指針指針的地方。
void add_node (struct Node **list, int n){
struct Node *new_node = malloc(sizeof(struct Node));
if(new_node == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
new_node->data = n;
new_node->next = *list;
*list = new_node;
}
因爲如果你使用的是dlistint_t *head
變量,而不是在函數參數使用dlistint_t **head
變量然後在變量head
在功能dlistint_t *add_dnodeint(dlistint_t **head, const int n);
所做的更改將是本地的這種方法。由於您使用的是Node*
,所以在變量head
中完成的更改對於該功能而言是本地的。如果你想反映這些變化,即使在函數調用後(你顯然想要),然後使用dlistint_t **head
。
如果您使用雙指針,您可以傳遞頭部的地址,以便您的函數可以修改實際的指針。這樣你就不需要返回新的頭部。
我會建議不要這種設計。最好有一個「list」結構,指向第一個和最後一個「節點」。這可以讓你通過傳遞它來修改列表,而不是直接使用節點 – Alexander
通常,你可以使用'bool add_dnodeint(dlistint_t ** head,int n)'和一個指向參數的指針和一個非指針返回值(或無返回值 - 'void'),或'dlistint_t * add_nodeint(dlistint_t * head,int n)'帶有一個簡單的指針參數和一個匹配的指針返回值(用作head = add_nodeint(head,newval) ;')。您通常不會同時執行這兩個操作 - 使用指向參數的指針並返回指針值。請注意,'const int n'幾乎沒有意義,因爲'n'不是一個指針。 –