Head First C学习日志 第六章用堆进行动态存储

时间秒杀一切 提交于 2019-12-03 05:16:08

书中的例子是,在多座岛屿间规划航线,并记录,将岛屿作为节点,数据结构如下

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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!