书中的例子是,在多座岛屿间规划航线,并记录,将岛屿作为节点,数据结构如下
typedef struct island {
char *name;
char *opens;
char *closes;
struct island *next;
} island;
注意,递归结构(含有指向相同类型的指针)不能为匿名结构,结构中相同类型的指针,在c语法中不允许通过别名来声明它。
创建create,display,release函数
create:
island *create(char *name) {
island *i = malloc(sizeof(island));
i->name = strdup(name);
i->opens = "09:00";
i->closes = "17:00";
i->next = NULL;
return i;
}
分配sizeof(island)大小的堆内存,并将地址给i,malloc的返回值是void*类型,可以充当任何类型指针赋值操作的右值,但是有的编译器可能会警告。
给成员赋值:i->name=strdup(name);strdup的含义是在内存中拷贝name,并返回地址,返回值类型为char* ,之所以这么做,是因为name只是用做接收输入的字符串,在内存中的位置固定,且内容会不断更新,如果直接使用name,那么就会有多个节点(i->name)指向同一个地址,结果就是,多个岛屿的名字都是最后一次输入的那个。
i->next=NULL;由于创建岛屿时不知道航线的下一个目的地是哪,所以逻辑上要置空,还有一个原因就是,如果不把指针置为NULL,那么指向的内存位置是不确定的,容易导致意想不到的问题。
display:
void display(island *start) {
island *i = start;
for (; i != NULL; i = i->next)
printf("Name:%s\n open:%s-%s\n", i->name, i->opens, i->closes);
}
将链表(航线)的起始指针传入,使用一个island类型的指针进行遍历,这个指针充当的是游标/迭代器。
release:释放内存
void release(island *start) {
island *i = start;
island *next = NULL;
for (; i != NULL; i = next) {
next = i->next;
free(i->name);
free(i);
}
printf("finish releasing.\n");
}
使用两个island类型指针从起始位置开始进行顺序释放。逻辑步骤:将i指向起始位置,如果i指向的位置的next不为空,next指向起始节点的下一个节点,释放i,将i指向next指向的位置,然后循环。
free()接收一个void*指针,返回值类型为void,注意一点:free(i)之前,要先把i->name释放掉,还记得吗,我们用strdup拷贝的name,如果直接free(i),那么拷贝的这个name的那部分内存,就再也访问不到了,没有人知道他的地址,造成内存泄漏,free函数并没有那么智能,所以我们要手动的将这部分内存释放掉,然后再free(i)。
main函数:
int main() {
printf("Game on\n");
island *start = NULL;
//i as a iterator
island *i = NULL;
island *node = NULL;
char name[80];
for (; fgets(name, 80, stdin); i = node) {
if (name[strlen(name) - 1] == '\n')
name[strlen(name) - 1] = 0;
//node leads to a piece of storage which contains the new island,the 'node' pointer changes every time you create a new island.
node = create(name);
if (start == NULL) {
start = node;
}
if (i != NULL) {
i->next = node;
}
}
display(start);
release(start);
return 0;
}
创建3个island指针,start代表该链表(航线)的起始位置,i作为迭代器将多个节点串联起来,node是新创建的island,每次创建都会更新node的地址,链表中每个节点只是一段内存(连续或不连续),并没有实际的名称。
逻辑步骤:接收一个island名,创建island,用node指针标记这一新建节点,如果当前start为空,将start赋值为node,如果i不为空,将i->next指向node,最后i=node,将i指向新创建的节点(为连接下一个节点做准备),循环这一步骤。完成这一系列操作后,node,i,i->next似乎都指向同一块内存。
单链表的创建在逻辑上绝对不会有太大出入,一个递归结构作为节点,循环创建节点,用一个临时指针串联所有节点,只start起始指针标记这一链表。
代码已上传到github:https://github.com/AlexTuan1024/egsonhfc.git
来源:oschina
链接:https://my.oschina.net/u/2491285/blog/618342