2013-07-04 76 views
0

我有一個關於在C中單獨鏈接列表中追加和投射新元素的問題。我在決定詢問之前做了一些研究,並找到了一些similar question的答案,它們在一定程度上解決了我的疑問,但是我仍然沒有完全理解爲什麼有些鑄件是必要的以取悅編譯器。投射新元素將它們追加到一個單獨鏈接列表中

我用gcc在Ubuntu 12.04 LTS:

$ gcc --version 
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 
Copyright (C) 2011 Free Software Foundation, Inc. 

所以我實現了下面的代碼:

1 #include <stdio.h> 
2 #include <stdlib.h> 
3 
4 typedef struct { 
5  struct node* next; 
6  int data; 
7 } node; 
8 
9 node* appendElement(node* head, int data); 
10 node* removeElement(node* head, int data); 
11 
12 int main(int argc, char** args){ 
13  //main code    
14  return 0; 
15 } 
16 
17 node* appendElement(node* head, int data){ 
18  node* newElement; 
19  if(head == NULL){ 
20   if((newElement = malloc(sizeof(node))) != NULL){ 
21    newElement->data = data; 
22    newElement->next = NULL; 
23    return newElement; 
24   } 
25   else{ 
26    fprintf(stderr, "Error"); 
27    return NULL; 
28   } 
29  } 
30  else{ 
31   node* n = head; 
32   while(n->next != NULL){ 
33    n = (node*)n->next; 
34   } 
35   if((newElement = malloc(sizeof(node))) != NULL){ 
36    newElement->data = data; 
37    newElement->next = NULL; 
38    n->next = (void*)newElement; 
39    return head; 
40   } 
41   else{ 
42    fprintf(stderr, "Error"); 
43    return NULL; 
44   } 
45  } 
46 } 
47 
48 node* removeElement(node* head, int data){ 
49  node* aux; 
50  if(head == NULL){ 
51   printf("Empty list, nothing to remove.\n"); 
52   return NULL; 
53  } 
54  else if(head->data == data){    
55    aux = (node*)head->next; 
56    free(head); 
57    return aux; 
58   } 
59   else{ 
60    node* n = head;   
61    while(n->next != NULL){ 
62     aux = (node*)n->next; 
63     if(aux->data == data){ 
64      n->next = aux->next; 
65      free(aux);     
66      return head; 
67     } 
68     n = (node*)n->next; 
69    } 
70    printf("Can't find %d in list.\n", data); 
71    return head;  
72   } 
73 } 

從答案我看了一個可以改變:

4 typedef struct { 
5  struct node* next; 
6  int data; 
7 } node; 

納入:

4 typedef struct _node { 
5  struct _node* next; 
6  int data; 
7 } node; 

,以避免在以下行的顯式轉換:

33 n = (node*)n->next; 
38 n->next = (void*)newElement; 
62 aux = (node*)n->next; 
68 n = (node*)n->next; 

正如預期的那樣,它的工作原理。我知道編譯器「不喜歡」使用未定義的結構。 (並且malloc的參數可以是newElement。)

我的問題是:如果不想更改結構聲明會怎麼樣?爲了讓編譯器感到高興,爲什麼需要那些鑄件?即使沒有這些鑄件,我相信該計劃仍然有效。

特別是,鑄造到void*我不得不在38行實施,根本沒有說服我。我知道void*是一個通用指針,因此每個指針都可以沒有問題地被降級,這就是我使用它的原因。

也許我對結構聲明的理解和typedef不如我想象的那麼好。謝謝你的時間。

編輯:更正了一些代碼更清晰。

+0

'if(node * newElement = malloc(sizeof(node))!= NULL)' - 這不應該編譯。 – Nobilis

+0

哎呀,謝謝你的擡頭,諾比利斯。 – herensuge

回答

0

你的結構受到嚴重定義:

typedef struct { 
    struct node* next; 
    int data; 
} node; 

第二行聲明next作爲指針到名爲node未知結構。這是未知的,因爲你還沒有宣佈它。將struct node* next更改爲struct junk* next,編譯將產生相同的結果。編譯器可以繼續超越這一點,因爲它不需要知道「節點」有多大,它只需要知道這是一個指針。

這是正常的規定,諸如此類的事情:

struct node { 
    struct node* next; 
    int data; 
}; 
typedef struct node node; 

這工作,因爲編譯器來讓你參考,它知道struct node是什麼任務的時間。在你的版本中,你永遠不會定義什麼是struct node。請注意,我在typedef中使用了與結構中相同的名稱,即'node'。這是可以的,因爲typedefs和struct是不同的名稱空間(因此可以重疊)。

0

像以下聲明的結構是好的。

#include<stdio.h> 
typedef struct node 
{ 
    int data; 
    struct node *next; 
}node; 

int main() 
{ 
    node n1, *pn1, *pn2; 
    pn1 = &n1; 
    pn2 = (node *)malloc(sizeof(node)); 
    pn1->data = 1; 
    pn1->next = NULL; 
    pn2->data = 2; 
    pn2->next = pn1; 
    printf("%d\n", pn2->data); 
    printf("%d\n", pn2->next->data); 
    return 0; 
} 

我測試它在MS CL編譯器,它工作正常。你可以免費使用指針。

相關問題