0

Cの単一リンクリストに新しい要素を追加してキャストすることについて質問があります。質問する前にいくつかの調査を行い、同様の質問に対するいくつかの回答を見つけました。これは私の疑問をある程度解決しますが、まだ解決していませんコンパイラを喜ばせるためにいくつかのキャストが必要な理由を完全に理解しました。

Ubuntu 12.04 LTS で gcc を使用しています。

$ 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  }

私が読んだ答えから、1つは変わる可能性があります:

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思ったほど良くありません。御時間ありがとうございます。

編集:より明確にするためにいくつかのコードを修正しました。

4

2 に答える 2

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 コンパイラでテストしたところ、問題なく動作しました。ポインターのキャストから解放されます。

于 2013-07-04T03:57:41.080 に答える
0

あなたの構造は正しく定義されていません:

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

next2 行目では、 という名前の未知の構造体へのポインターとして宣言していますnode。まだ宣言していないので不明です。に変更struct node* nextするstruct junk* nextと、コンパイルは同じ結果になります。コンパイラは、「ノード」の大きさを知る必要はなく、これがポインタであることを知るだけでよいため、この時点を超えて続行できます。

そのようなことを次のように定義するのが普通です。

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

これが機能するのは、コンパイラが参照する代入を行うまでに、a が何であるかを認識しているためstruct nodeです。あなたのバージョンでは、 astruct nodeが何であるかを定義することはありません。構造体と同じ名前、つまり「ノード」を typedef で使用したことに注意してください。typedef と struct は異なる名前空間であるため (したがって重複する可能性があるため)、これは問題ありません。

于 2013-07-04T02:27:33.223 に答える