C 语言中的结构体

C 语言中的结构体能够使我们实现类型的自定义,满足定义一些特殊变量的需求。

结构体定义

结构体一般定义为:

struct structname
{
    datatype member1;
    datatype member2;
    datatype member3;
};
  • structname 代表该自定义结构体名
  • datatype 代表该结构体成员类型
  • member 代表该结构体成员名
  • 结构体定义后一定要加分号

结构体构造类型

无名结构类型

#include <stdio.h>

struct
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}stu1;

struct
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}stu2,stu3;

int main()
{
    struct
    {
        int num;
        char name[10];
        int math;
        int chinese;
        int english;
    }stu4;

    return 0;
}
  • 这种构造方法用在变量只定义一次的场合
  • 如果在不同的区域需要定义类型相同的变量,则会出现代码冗余
  • 但这种构造方法不会增加类型名
  • 但是要注意全局变量会初始化为 0,局部变量会初始化为随机值
  • 变量定义后一定要加分号

有名构造类型

#include <stdio.h>

struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}stu1;

struct Worker
{
    int num;
    char name[10];
    char department[20];
};

int main()
{
    struct Student stu2;
    struct Worker worker1;

    return 0;
}
  • 这种构造方法可以随时随地定义变量
  • 结构体类型名称是 struct structname,struct 关键字不能省略
  • 从上边的代码可以看出 struct stuctname stu2 与 int a 的作用类似
  • 也可以说成是 struct 新构造了一种类型供用户使用
  • 类型定义或变量定义后一定要加分号

别名构造类型

#include <stdio.h>

typedef struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}STU;

int main()
{
    STU stu;

    return 0;
}
  • 一般情况下,为了缩短自定义类型名,都会采用这种写法
  • 结构体定义最好在程序的开头部分,在头文件声明之后
  • 别名构造不能直接在结构体定义后直接声明变量
  • 类型定义后一定要加分号

结构体变量初始化及成员访问

初始化

结构体也属于构造类型,可以参考同属于构造类型的数组的变量初始化方法,即:

  • 在定义变量的时候进行初始化
  • 或者在定义之后分别对成员进行赋值
#include <stdio.h>
#include <string.h>

struct
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}stu1 = {10,"123",20,30,40},stu2 = {10,"123",20,30,40};

struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
};

int main()
{
    struct Student stu3 = {10,"123",20,30,40},stu4;

    stu4.num = 10;
    strcpy(stu4.name,"123");
    stu4.math = 20;
    stu4.chinese = 30;
    stu4.english = 40;

    printf("stu1.num = %d\n",stu1.num);
    printf("stu1.name = %s\n",stu1.name);
    printf("stu1.math = %d\n",stu1.math);
    printf("stu1.chinese = %d\n",stu1.chinese);
    printf("stu1.english = %d\n",stu1.english);

    printf("stu2.num = %d\n",stu2.num);
    printf("stu2.name = %s\n",stu2.name);
    printf("stu2.math = %d\n",stu2.math);
    printf("stu2.chinese = %d\n",stu2.chinese);
    printf("stu2.english = %d\n",stu2.english);

    printf("stu3.num = %d\n",stu3.num);
    printf("stu3.name = %s\n",stu3.name);
    printf("stu3.math = %d\n",stu3.math);
    printf("stu3.chinese = %d\n",stu3.chinese);
    printf("stu3.english = %d\n",stu3.english);

    printf("stu4.num = %d\n",stu4.num);
    printf("stu4.name = %s\n",stu4.name);
    printf("stu4.math = %d\n",stu4.math);
    printf("stu4.chinese = %d\n",stu4.chinese);
    printf("stu4.english = %d\n",stu4.english);

    return 0;
}

结果为:

stu1.num = 10
stu1.name = 123
stu1.math = 20
stu1.chinese = 30
stu1.english = 40
stu2.num = 10
stu2.name = 123
stu2.math = 20
stu2.chinese = 30
stu2.english = 40
stu3.num = 10
stu3.name = 123
stu3.math = 20
stu3.chinese = 30
stu3.english = 40
stu4.num = 10
stu4.name = 123
stu4.math = 20
stu4.chinese = 30
stu4.english = 40
  • 变量 stu1,stu2 初始化的形式虽然看起来很奇怪,但其实是符合定义的
  • 结构体如果有初始化值的时候,一般采用变量 stu3 的形式
  • 结构体如果初始化值位置的时候,一般会采用变量 stu4 的形式

上边的程序中有一段话可能需要解释一下:

stu4.num = 10;
strcpy(stu4.name,"123");
stu4.math = 20;
stu4.chinese = 30;
stu4.english = 40;

其中 str4.name 是用 strcpy 函数进行赋值的,为什么不能也用 stu4.name = “123”; 这样的形式呢?

  • stu4.name 对应成员 name 的首地址,该地址在变量 stu4 定义的时候已经确定了,所以是个常量
  • “123” 实际上对应的是存储在只读数据段的首地址,实际也是常量
  • 用 stu4.name = “123”; 进行赋值自然就会报错
  • 用 *stu4.name = “123”; 也会报错,因为你不知道字符串常量 “123” 所在的地址对应的字符串是什么东西
  • 我们需要将 “123” 对应的字符串重新复制到 stu4.name 对应的地址中,因此才会使用 strcpy 函数

成员访问

. 成员运算符

在初始化的时候,我们使用 stu.xxx 的形式来指向结构体变量的成员,中间的那个点也是一个运算符,叫做成员运算符。

使用 . 运算符能够访问到结构体变量的成员,我们可以试试手动输入进行赋值。

#include <stdio.h>

struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
};

int main()
{
    struct Student stu;

    printf("Please input number:");
    scanf("%d",&stu.num);
    printf("Please input name:");
    scanf("%s",stu.name);
    printf("Please input math:");
    scanf("%d",&stu.math);
    printf("Please input chinese:");
    scanf("%d",&stu.chinese);
    printf("Please input english:");
    scanf("%d",&stu.english);

    printf("stu.num = %d\n",stu.num);
    printf("stu.name = %s\n",stu.name);
    printf("stu.math = %d\n",stu.math);
    printf("stu.chinese = %d\n",stu.chinese);
    printf("stu.english = %d\n",stu.english);

    return 0;
}

-> 间接成员运算符

从之前的程序可以看出,当直接定义结构体变量时,可以用 . 成员运算符直接进行访问。

那么间接成员运算符就主要是针对结构体指针来说的,可以使用间接成员运算符访问结构体指针指向的变量成员。

#include <stdio.h>

typedef struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}STU;

int main()
{
    STU stu1;
    STU *ps = &stu1;

    printf("Please input number:");
    scanf("%d",&ps->num);
    printf("Please input name:");
    scanf("%s",ps->name);
    printf("Please input math:");
    scanf("%d",&ps->math);
    printf("Please input chinese:");
    scanf("%d",&ps->chinese);
    printf("Please input english:");
    scanf("%d",&ps->english);

    printf("ps->num = %d\n",ps->num);
    printf("ps->name = %s\n",ps->name);
    printf("ps->math = %d\n",ps->math);
    printf("ps->chinese = %d\n",ps->chinese);
    printf("ps->english = %d\n",ps->english);

    printf("(*ps).num = %d\n",(*ps).num);
    printf("(*ps).name = %s\n",(*ps).name);
    printf("(*ps).math = %d\n",(*ps).math);
    printf("(*ps).chinese = %d\n",(*ps).chinese);
    printf("(*ps).english = %d\n",(*ps).english);

    return 0;
}
  • 运行之后可以发现,两次的输出结果是一样的
  • 也就是说不管是 . 还是 ->,都是有效的
  • 两个运算符作用也是等价的

有时也不直接从栈上开辟内存,而是从堆上,程序本身没有什么大的区别。

#include <stdio.h>
#include <stdlib.h>

typedef struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}STU;

int main()
{
    STU *ps = (STU *)malloc(sizeof(STU));

    printf("Please input number:");
    scanf("%d",&ps->num);
    printf("Please input name:");
    scanf("%s",ps->name);
    printf("Please input math:");
    scanf("%d",&ps->math);
    printf("Please input chinese:");
    scanf("%d",&ps->chinese);
    printf("Please input english:");
    scanf("%d",&ps->english);

    printf("ps->num = %d\n",ps->num);
    printf("ps->name = %s\n",ps->name);
    printf("ps->math = %d\n",ps->math);
    printf("ps->chinese = %d\n",ps->chinese);
    printf("ps->english = %d\n",ps->english);

    printf("(*ps).num = %d\n",(*ps).num);
    printf("(*ps).name = %s\n",(*ps).name);
    printf("(*ps).math = %d\n",(*ps).math);
    printf("(*ps).chinese = %d\n",(*ps).chinese);
    printf("(*ps).english = %d\n",(*ps).english);

    return 0;
}

成员地址

之前我们说过数组中的元素地址是线性的,但其实结构体变量中的成员地址也是线性的。看下边一段程序:

#include <stdio.h>
#include <stdlib.h>

typedef struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}STU;

int main()
{
    STU stu = {10,"123",20,30,40};

    printf("&stu.num = %p,stu.num = %d\n",&stu.num,stu.num);
    printf("&stu.name = %p,stu.name = %s\n",stu.name,stu.name);
    printf("&stu.math = %p,stu.math = %d\n",&stu.math,stu.math);
    printf("&stu.chinese = %p,stu.chinese = %d\n",&stu.chinese,stu.chinese);
    printf("&stu.english = %p,stu.english = %d\n",&stu.english,stu.english);

    return 0;
}

结果为:

&stu.num = 0060FE94,stu.num = 10
&stu.name = 0060FE98,stu.name = 123
&stu.math = 0060FEA4,stu.math = 20
&stu.chinese = 0060FEA8,stu.chinese = 30
&stu.english = 0060FEAC,stu.english = 40

从上面结果来看:

  • 结构体和数组某些地方是相通的
  • 但数组中元素类型相同,结构体中成员类型不同
  • 数组中元素能用指针偏移访问,但结构体一般不推荐这样做
  • 代替数组中的指针偏移,结构体中提供了成员访问运算符和成员名来作为单个成员访问的工具

变量赋值

有时候我们还会要进行变量赋值,如果进行成员间赋值是很麻烦的。看下面的程序:

#include <stdio.h>
#include <stdlib.h>

typedef struct Student
{
    int num;
    char name[10];
    int math;
    int chinese;
    int english;
}STU;

int main()
{
    STU stu1 = {10,"123",20,30,40},stu2;
    stu2 = stu1;

    printf("&stu1.num = %p,stu1.num = %d\n",&stu1.num,stu1.num);
    printf("&stu1.name = %p,stu1.name = %s\n",stu1.name,stu1.name);
    printf("&stu1.math = %p,stu1.math = %d\n",&stu1.math,stu1.math);
    printf("&stu1.chinese = %p,stu1.chinese = %d\n",&stu1.chinese,stu1.chinese);
    printf("&stu1.english = %p,stu1.english = %d\n",&stu1.english,stu1.english);

    printf("&stu2.num = %p,stu2.num = %d\n",&stu2.num,stu2.num);
    printf("&stu2.name = %p,stu2.name = %s\n",stu2.name,stu2.name);
    printf("&stu2.math = %p,stu2.math = %d\n",&stu2.math,stu2.math);
    printf("&stu2.chinese = %p,stu2.chinese = %d\n",&stu2.chinese,stu2.chinese);
    printf("&stu2.english = %p,stu2.english = %d\n",&stu2.english,stu2.english);

    return 0;
}

结果为:

&stu1.num = 0060FE94,stu1.num = 10
&stu1.name = 0060FE98,stu1.name = 123
&stu1.math = 0060FEA4,stu1.math = 20
&stu1.chinese = 0060FEA8,stu1.chinese = 30
&stu1.english = 0060FEAC,stu1.english = 40
&stu2.num = 0060FE78,stu2.num = 10
&stu2.name = 0060FE7C,stu2.name = 123
&stu2.math = 0060FE88,stu2.math = 20
&stu2.chinese = 0060FE8C,stu2.chinese = 30
&stu2.english = 0060FE90,stu2.english = 40

从上面的结果可以看出:

  • 结构体变量之间能够进行互相赋值
  • 不管成员是什么类型,都能够进行赋值

结构体数组

既然知道了结构体类型的定义和初始化方式,之前我们也知道了二维数组的定义和初始化方式,那么结构体数组就不算是太大的问题了。

定义和初始化

#include <stdio.h>

typedef struct Student
{
    int num;
    char name[10];
    int score;
}STU;

int main()
{
    STU stu[3] = {{101,"Tom",70},{102,"Jim",80},{103,"Lily",90}};
//    STU stu[3] = {101,"Tom",70,102,"Jim",80,103,"Lily",90};

    for (unsigned int i = 0;i < sizeof(stu)/sizeof(stu[0]);i++)
    {
        printf("stu.num = %d\n",stu[i].num);
        printf("stu.name = %s\n",stu[i].name);
        printf("stu.score = %d\n",stu[i].score);
    }

    return 0;
}

结果是:

stu.num = 101
stu.name = Tom
stu.score = 70
stu.num = 102
stu.name = Jim
stu.score = 80
stu.num = 103
stu.name = Lily
stu.score = 90

从程序段可以看出:

  • 结构体数组的初始化和二维数组初始化方法类似
  • 如果有部分成员未初始化,就初始化为零
  • 注释掉的初始化方法一般不建议采用

结构体类型嵌套及其初始化

有时候,当某一项属性涉及到多个子项的时候,也会采用结构体类型嵌套的形式,可以增加程序的可读性。

#include <stdio.h>

//struct Score
//{
//    int math;
//    int chinese;
//    int english;
//};

typedef struct Student
{
    int num;
    char name[10];
    struct
    {
        int math;
        int chinese;
        int english;
    }score;
}STU;

int main()
{
    STU stu = {101,"Tom",{10,20,30}};
//    STU stu = {101,"Tom",10,20,30};

    printf("stu.num = %d\n",stu.num);
    printf("stu.name = %s\n",stu.name);
    printf("stu.score.math = %d\n",stu.score.math);
    printf("stu.score.chinese = %d\n",stu.score.chinese);
    printf("stu.score.english = %d\n",stu.score.english);

    return 0;
}

结果为:

stu.num = 101
stu.name = Tom
stu.score.math = 10
stu.score.chinese = 20
stu.score.english = 30

从上边的结果可以看出:

  • 结构体类型嵌套的只能是结构体类型的变量,从语法角度看,嵌套一个结构体类型就好像在结构体中只写了一个 “int”,是无意义的
  • 为了改善程序的可读性,也可以将嵌套的结构体类型变量放在结构体类型外部定义
  • 结构体类型嵌套时的初始化大致不变,有时候为了以示区分,也将结构体类型变量单独加个括号
  • 注释的初始化方法也能正常显示,但不推荐用
  • 对于结构体类型变量的访问也就需要多加一层才能实现正常访问

结构体类型变量与函数

结构体类型变量做参数并返回

#include <stdio.h>
#include <stdlib.h>

typedef struct complex
{
    float re;
    float im;
}COM;

COM com_plus(COM com1, COM com2)
{
    COM res;
    res.re = com1.re + com2.re;
    res.im = com1.im + com2.im;
    return res;
}

int main()
{
    COM com1 = { 1.0f, 2.0f };
    COM com2 = { 3.0f, 4.0f };
    COM res = com_plus(com1, com2);
    printf("res:re = %f ,im = %f\n", res.re, res.im);
    return 0;
}

结果为:

res:re = 4.000000 ,im = 6.000000

结构体类型指针做参数

#include <stdio.h>
#include <stdlib.h>

typedef struct complex
{
    float re;
    float im;
}COM;

COM com_plus(COM *pcom1, COM *pcom2)
{
    COM res;
    res.re = pcom1->re + pcom2->re;
    res.im = pcom1->im + pcom2->im;
    return res;
}

int main()
{
    COM com1 = { 1.0f, 2.0f };
    COM com2 = { 3.0f, 4.0f };
    COM res = com_plus(&com1, &com2);
    printf("res:re = %f ,im = %f\n", res.re, res.im);
    return 0;
}

结果是:

res:re = 4.000000 ,im = 6.000000

从上边的结果可以看出:

  • 结构体类型变量做参数并没有什么特殊的,先对某些变量进行赋值,再执行函数操作
  • 用结构体类型变量做参数要使用成员运算符
  • 使用结构体类型指针做参数要使用间接成员运算符
  • 但是用结构体类型指针会节省内存,毕竟指针是固定字节大小的
  • 要注意,一般情况下是不以函数中声明的结构体类型指针作为返回值的,因为地址对应的空间可能已经被释放

结构体类型中的内存对齐

结构体类型就好像 int,float 这样的关键字一样,是不占用内存的,但是结构体类型的变量确实要占用内存的,并且还有点特殊。看下边一段程序:

#include <stdio.h>
#include <stdlib.h>

typedef struct Student
{
    short num;
    char sex;
    int score;

}STU;

int main()
{
    STU stu = {10,'m',80};

    printf("&stu.num = %p,stu.num = %d\n",&stu.num,stu.num);
    printf("&stu.sex = %p,stu.sex = %c\n",&stu.sex,stu.sex);
    printf("&stu.score = %p,stu.score = %d\n",&stu.score,stu.score);

    return 0;
}

结果是:

&stu.num = 0060FEA8,stu.num = 10
&stu.sex = 0060FEAA,stu.sex = m
&stu.score = 0060FEAC,stu.score = 80

当时我们只是说明了结构体类型的变量的内存空间也是线性排列的,并没有涉及到实际的内存地址。但对于上面的结果,我们能够看出该变量首地址对应 0060FEA8,下一个成员地址是 0060FEAA,再下一个地址是 0060FEAC。为什么不是 0060FEAA 和 0060FEAB 呢?我们就从这里引入我们的问题。

为什么要内存对齐

对于上面的程序,由于变量的内存空间是线性的,那么对于该变量各成员的位置有上图中几种方案,由结果我们知道选择的是方案 B。

我们知道计算机地址总线是固定的,一般为 32 或者 64,这里以 32 为例。也就是说计算机一次能够读取四个字节的地址,然后我们看看上面三个方案的不同:

  • 方案 A:要读取 num 时,先读取前四个字节,然后抽取 num 的部分
    • 要读取 name  时,先读取前四个字节,然后抽取 name 的部分
    • 要读取 score 时,先读取前四个字节,然后抽取 score 的前一部分,再读取后四个字节,然后抽取 score 的后一部分
  • 方案 B:要读取 num 时,先读取前四个字节,然后抽取 num 的部分
    • 要读取 name  时,先读取前四个字节,然后抽取 name 的部分
    • 要读取 score 时,直接读取后四个字节
  • 方案 C:要读取 num 时,先读取前四个字节,然后抽取 num 的部分
    • 要读取 name  时,先读取前四个字节,然后抽取 name 的部分
    • 要读取 score 时,直接读取后四个字节

从上面的结果结果我们知道,不同的方案数据读取的次数就不同,同时计算机所花费的时间就会不同。一个成员变量需要多个机器周期去读的现象,就叫做内存不对齐。也就是说利用内存对齐,虽然会浪费些空间而节省计算时间。这对于计算机来说是划算的。

方案 B 和方案 C 的好像空间和时间都是一样的,那为什么会使用方案 B 呢?那是因为内存对齐是有一定规则的。

内存对齐规则

  • 在 X86 架构中,Linux 默认为 #pragma pack(4)
  • 在 X86 架构中,Windows 默认为 #pragma pack(8)
  • Linux 最大支持 4 字节对齐

具体方法:

  1. 取 pack(n) 的值为 n(n = 1,2,4,8...),取结构体类型中成员类型所占的最大字节长度为 m,两者取较小即为外对齐大小 Y
  2. 将每一个结构体类型的成员字节长度与 Y 比较取较小者为 X 作为内对齐大小
  3. 所谓的按 X 内对齐,就是地址能被 x 整除的地方开始存放数据(数据起始地址为 0)
  4. 外对齐就是按照 Y 的值(Y 的最小整数倍),进行补空

这里把上边的程序修改后重新运行一下:

#include <stdio.h>
#include <stdlib.h>

typedef struct Student
{
    short num;
    char sex;
    int score;
    char access;
//    short grade;

}STU;

int main()
{
    STU stu = {10,'m',80,'y'};

    printf("The STU length is %d\n",sizeof(STU));

    printf("&stu.num = %p,stu.num = %d\n",&stu.num,stu.num);
    printf("&stu.sex = %p,stu.sex = %c\n",&stu.sex,stu.sex);
    printf("&stu.score = %p,stu.score = %d\n",&stu.score,stu.score);
    printf("&stu.access = %p,stu.access = %d\n",&stu.access,stu.access);
//    printf("&stu.grade = %p,stu.grade = %d\n",&stu.grade,stu.grade);

    return 0;
}

结果为:

The STU length is 12
&stu.num = 0060FEA4,stu.num = 10
&stu.sex = 0060FEA6,stu.sex = m
&stu.score = 0060FEA8,stu.score = 80
&stu.access = 0060FEAC,stu.access = 121

从上面的结果可以看出:

  • 有没有成员 grade,该结构体类型的长度都是 12
  • 外对齐决定结构体类型的字节长度
  • 内对齐决定结构体内部的排列分布

注意事项

结构体类型中指针要慎用

看下边一段代码:

#include <stdio.h>
#include <string.h>

typedef struct Student
{
    short num;
    char *name;
    int score;
}STU;

int main()
{
    STU stu;

    stu.num = 10;
    strcpy(stu.name,"123");
    stu.score = 80;

    printf("&stu.num = %p,stu.num = %d\n",&stu.num,stu.num);
    printf("&stu.name = %p,stu.name = %p,*stu.name = %c\n",&stu.name,stu.name,*stu.name);
    printf("&stu.score = %p,stu.score = %d\n",&stu.score,stu.score);

    return 0;
}

上面的代码看似没有问题,出于节约内存的考量,我们将 char name[10]  换成了 char *name,但是结果并不是我们想象的那样,那么问题出现在哪里呢?

  • 我们构造了一个结构体类型,并定义了一个结构体类型的变量
  • 该变量的首地址在定义时已经被分配的
  • 该变量中的成员地址是线性的,各个成员的地址也就随之确定
  • 该变量没有进行初始化,所以初始值是随机的
  • name 指针指向的地址也就是随机的,也就是说我们不知道指向的这段内存是什么东西
  • 通过 strcpy 函数对该地址进行写入操作自然会出错
  • 结构体类型的指针成员使用时一定要注意

将上边的程序改写为:

#include <stdio.h>

typedef struct Student
{
    short num;
    char *name;
    int score;
}STU;

int main()
{
    STU stu;

    stu.num = 10;
    stu.name = "123";
    stu.score = 80;

    printf("&\"123\" = %p\n","123");
    printf("&stu.num = %p,stu.num = %d\n",&stu.num,stu.num);
    printf("&stu.name = %p,stu.name = %p,stu.name = %s\n",&stu.name,stu.name,stu.name);
    printf("&stu.score = %p,stu.score = %d\n",&stu.score,stu.score);

    return 0;
}

结果为:

&"123" = 00404064
&stu.num = 0060FEA4,stu.num = 10
&stu.name = 0060FEA8,stu.name = 00404064,stu.name = 123
&stu.score = 0060FEAC,stu.score = 80

总结为一点就是:什么样的成员就执行什么样的操作

结构体类型变量与堆

上面提到的问题还可以用另外一种方法解决:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Student
{
    short num;
    char *name;
    int score;
}STU;

int main()
{
    STU *stu = (STU *)malloc(sizeof(STU));

    if (NULL == stu)
        return -1;

    stu->num = 10;
    stu->name = malloc(10);

    if (NULL == stu->name)
        return -1;

    strcpy(stu->name,"123");
    stu->score = 80;

    printf("&\"123\" = %p\n","123");
    printf("&stu->num = %p,stu->num = %d\n",&stu->num,stu->num);
    printf("&stu->name = %p,stu->name = %p,stu->name = %s\n",&stu->name,stu->name,stu->name);
    printf("&stu->score = %p,stu->score = %d\n",&stu->score,stu->score);

    free(stu->name);

    stu->name = NULL;

    free(stu);

    stu = NULL;

    return 0;
}

结果为:

&"123" = 00404064
&stu->num = 00C616F0,stu->num = 10
&stu->name = 00C616F4,stu->name = 00C61708,stu->name = 123
&stu->score = 00C616F8,stu->score = 80

上面的方法也能够解决之前提到的问题。但是在使用上述的方法时,一定要注意释放内存,并且是由内而外的释放内存。

发布了77 篇原创文章 · 获赞 5 · 访问量 4865

猜你喜欢

转载自blog.csdn.net/SAKURASANN/article/details/104533132