我有一个关于在C中单独链接列表中添加和转换新元素的问题。我在决定提问之前做了一些研究,并找到了similar question的一些答案,这在一定程度上解决了我的疑问,但是我仍然没有完全理解为什么有些铸件是为了取悦编译器所必需的。
我在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 }
从我读到的答案可以改变:
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
。)
我的问题是:如果一个人不想改变结构声明怎么办?为什么那些铸件必须使编译器满意?我相信即使没有这些演员,该节目仍然有效。
特别是,我必须在第38行实施的void*
投射并不能说服我。我知道void*
是一个通用指针,因此每个指针都可以毫无问题地进行下调,这就是我使用它的原因。
也许我对结构声明和typedef
的理解并不如我想象的那么好。谢谢你的时间。
编辑:更正清某些代码。
答案 0 :(得分: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”。这是可以的,因为typedef和structs是不同的名称空间(因此可以重叠)。
答案 1 :(得分: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编译器中测试它,它工作正常。你可以免于投射指针。