C语言----链表理论(高阶篇三十六)

  动态内存分配

    程序1

      sizeof与结构

//36-1 sizeof与结构.c

#include <stdio.h>
#pragma    pack(1)    //字节对齐

struct student     //定义结构类型
{ 
    char name[9];
    char sex[3];
    int age;
}*pstu, stu = {"王什","",46};

main()
{
    double d, *pd = &d;    //双精度浮点型
    printf("%d\n", sizeof(struct student));  //结构内存
    printf("%d\n", sizeof(stu));     //结构变量内存
    printf("%d\n", sizeof(pstu));     //结构指针内存

    printf("%d\n", sizeof(double));     //双精度浮点型内存
    printf("%d\n", sizeof(d));     //双精度浮点型变量内存
    printf("%d\n", sizeof(pd));     //双精度浮点型变量内存

}

 

    ※在sizeof中使用变量和类型效果一样,如果计算的是变量,它只会计算出变量对应类型所占的字节数。

 

 

    普通的变量定义,在定义时分配内存,函数结束时释放内存,这一切都由系统自动完成。在C语言中,程序员也可以自由地,不受系统控制地手动分配内存。若要手动分配内存,需要用到以下知识点:

      ※使用sizeof函数计算变量或类型的大小

      ※使用malloc函数、free函数分配内存

      ※使用指针指向已分配的内存。

    程序2

      无名变量

// 36-2无名变量.c

#include <stdio.h>

main()
{
    int *p1, *p2, *p3;   //定义三个整型指针
    p1 = (int*)malloc(sizeof(int));   //p1指针分配4字节内存空间
    p2 = (int*)malloc(sizeof(int));   //p2指针分配4字节内存空间
    p3 = (int*)malloc(sizeof(int));   //p3指针分配4字节内存空间
    printf("变量地址:%d,%d,%d\n", p1, p2, p3);  //分配的地址
    *p1 = 10;
    *p2 = 20;
    *p3 = 30;
    printf("变量内容:%d,%d,%d\n", *p1, *p2, *p3);  //内容

    free(p1);    //释放内存
    free(p2);
    free(p3);
    printf("变量内容:%d,%d,%d\n", *p1, *p2, *p3);  //释放后的内容
}

    ※malloc和free通常配对使用,malloc的内存如果没有用free释放,会造成“内存泄露”。

  链表原理

    使用数组存储数据时,所有的数据在内存中连成一片,需要取出某个数据,只要报上它在内存中的房间编号(数组下标)即可马上取出。

    数组也有缺点,它必须预先分配好一些内存,如果这些内存未全部使用,其它的就浪废了。这在字符串的使用中尤为明显:

      char str[100]=”hello!”;

    程序员定义这个字符串最大能接受99个字符。但是在这里因为实际需求只用了前面7个字符,后面的93个字节就浪废了,浪废率达到90%。

    于是软件工程师们就想出“链表”这种存储方法,它的内存结构如下:

      

    在C语言中,一般用结构表示链表:

      struct student

      {

        char name[9]; /*姓名*/

        int age; /*年龄*/

        struct student *pNext; /*下一结点*/

      };

 

 

    ※老师带小朋友游玩时,老师用手拉着第一个小朋友,第一个小朋友又拉着后面的小朋友,以此类推……

    这里的“头指针”可以比作老师的手,后面的“指针”就像小朋友的手,最后一个小朋友后面没有拉人,所以它设置为NULL。

    链表这种结构,就像锁链一样,一环扣着一环,有一个环坏了,后面所有的结点都会丢失,这就是链表的特点。

 

    程序3

      手拉手的小朋友

// 36-3手拉手小盆友(链表简单使用).c

#include <stdio.h>

struct  kid      //小盆友结构变量
{
    char name[9];
    int age;
    struct kid *pHand;    //指针指向下一个小盆友
};

main()
{
    struct kid k1 = { "小名",3 };
    struct kid k2 = { "小红",4 };
    struct kid k3 = { "小冰",6 };
    k1.pHand = &k2;   //第一个小朋友拉着第二个小盆友的手
    k2.pHand = &k3;      //第二个小朋友拉着第三个小盆友的手
    k3.pHand = NULL;
    printf("%s拉着的小盆友是:%s\n", k1.name, k1.pHand->name);  //换种写法: (*k1.pHand).name
    printf("%s拉着的小盆友是:%s\n", k2.name, k2.pHand->name);
}

  名词解释

    结点(Node):

      在《数据结构》中,结点通常表示一个数据单位,比如在数组中,数组元素可称为结点。在“树”结构中,每个分支元素也称为结点。如:设系为根结点,班是系的子结点,学生是班的子结点。反推过去,系是班的父结点,班是学生的父结点,系是所有子结点的祖宗结点。

      链表和数组都不是用来描述父子关系的,它们通常用来描述“兄弟关系”,所以结点与结点的关系不像“树”结构这么复杂。

 

  作业

 

// 36-4练习.c

#include <stdio.h>
fut(int **s, int p[2][3])
{
    **s = p[1][1];   //指针与二维数组中   **s = *(*(s+0)+0)  取内容
}
main()
{
    int a[2][3] = { 1,3,5,7,9,11 }, *p;
    p = (int*)malloc(sizeof(int));     //定义一个无名变量
    fut(&p, a);   
    printf("%d\n", *p);    //结果是 : 9
}

 

 

 

posted @ 2021-11-15 11:05  httpcc  阅读(84)  评论(0编辑  收藏  举报