文章目录

  • 一、结构体中嵌套二级指针
    • 1、结构体中嵌套二级指针 类型声明
    • 2、为 结构体内的二级指针成员 分配内存
    • 3、释放 结构体内的二级指针成员 内存
  • 二、完整代码示例

一、结构体中嵌套二级指针


1、结构体中嵌套二级指针 类型声明

结构体中 嵌套 二级指针 , 二级指针 可以使用 指针数组 / 二维数组 / 自定义二级指针内存 三种内存模型的任意一种 ;

此处选择的模型是 自定义二级指针内存 ;

代码示例 :

/*** @brief The Student struct* 定义 结构体 数据类型 , 同时为该结构体类型声明 别名* 可以直接使用 别名 结构体变量名 声明结构体类型变量* 不需要在前面添加 struct 关键字*/
typedef struct Student
{// 声明变量时 , 会自动分配这 5 字节内存// 赋值时 , 可以直接使用 = 赋值字符串char name[5];int age;int id;// 声明变量时 , 只会为 4 字节指针分配内存// 具体的 字符串内存 需要额外使用 malloc 申请内存// 赋值时 , 必须使用 strcpy 函数 , 向堆内存赋值char *address;// 学生小组成员 , 由多个字符串组成// 二级指针 , 指向多个 一级指针// 每个 一级指针 指向 一个字符串// 此处的 二级指针 可以使用 指针数组 / 二维数组 / 自定义二级指针内存// 此处选择的模型是 自定义二级指针内存char **team;
}Student;

2、为 结构体内的二级指针成员 分配内存

为二级指针成员分配内存时 , 先为二级指针分配内存 , 再为一级指针分配内存 ;

核心业务逻辑 :

    // 为每个结构体的 address 成员分配内存for(i = 0; i < count; i++){// 为一级指针分配内存模型tmp[i].address = (char *)malloc(20);// 为 二级指针 内存模型分配内存 , 分配 3 个 一级指针 变量内存char **p = (char **)malloc(3 * sizeof(char *));// 为 二级指针 指向的 一级指针 分配内存for(j = 0; j < 3; j++){// 每个一级指针分配 10 字节数据p[j] = (char *)malloc(10 * sizeof(char));}// 将分配好内存的 二级指针 模型 , 赋值给结构体中的二级指针tmp[i].team = p;}

代码示例 :

/*** @brief create_student 堆内存中分配内存* 为二级指针成员分配内存时 , 先为二级指针分配内存 , 再为一级指针分配内存* @param array 二级指针 , 指向结构体数组* @return*/
int create_student(Student **array, int count)
{// 返回值int ret = 0;// 循环控制变量int i = 0, j = 0;// 临时变量Student *tmp = NULL;// 验证二级指针合法性if(array == NULL){ret = -1;return ret;}// 堆内存中申请内存tmp = (Student *)malloc(sizeof(Student) * count);// 初始化分配的内存memset(tmp, 0, sizeof(Student) * count);// 为每个结构体的 address 成员分配内存for(i = 0; i < count; i++){// 为一级指针分配内存模型tmp[i].address = (char *)malloc(20);// 为 二级指针 内存模型分配内存 , 分配 3 个 一级指针 变量内存char **p = (char **)malloc(3 * sizeof(char *));// 为 二级指针 指向的 一级指针 分配内存for(j = 0; j < 3; j++){// 每个一级指针分配 10 字节数据p[j] = (char *)malloc(10 * sizeof(char));}// 将分配好内存的 二级指针 模型 , 赋值给结构体中的二级指针tmp[i].team = p;}// 通过间接赋值 设置返回值*array = tmp;return ret;
}

3、释放 结构体内的二级指针成员 内存

释放内存时 , 先释放 二级指针 指向的 一级指针 的内存 , 再释放 二级指针 内存 ;

核心业务逻辑 :

    // 释放 每个结构体的 address 成员分配内存for(i = 0; i < count; i++){// 释放一级指针free((*array)[i].address);(*array)[i].address = NULL;// 释放二级指针指向的一级指针for(j = 0; j < 3; j++){if((*array)[i].team[j] != NULL){free( (*array)[i].team[j] );(*array)[i].team[j] = NULL;}}// 释放二级指针if((*array)[i].team != NULL){free( (*array)[i].team );(*array)[i].team = NULL;}}

代码示例 :

/*** @brief free_student 释放内存* 释放内存时 , 先释放 二级指针 指向的 一级指针 的内存 , 再释放 二级指针 内存* @param array* @return*/
int free_student(Student **array, int count)
{// 返回值int ret = 0;// 循环控制变量int i = 0, j = 0;// 验证二级指针合法性if(array == NULL){ret = -1;return ret;}// 释放 每个结构体的 address 成员分配内存for(i = 0; i < count; i++){// 释放一级指针free((*array)[i].address);(*array)[i].address = NULL;// 释放二级指针指向的一级指针for(j = 0; j < 3; j++){if((*array)[i].team[j] != NULL){free( (*array)[i].team[j] );(*array)[i].team[j] = NULL;}}// 释放二级指针if((*array)[i].team != NULL){free( (*array)[i].team );(*array)[i].team = NULL;}}// 释放 结构体内存free(*array);// 指针置空 , 防止野指针*array = NULL;return ret;
}

二、完整代码示例


完整代码示例 :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>/*** @brief The Student struct* 定义 结构体 数据类型 , 同时为该结构体类型声明 别名* 可以直接使用 别名 结构体变量名 声明结构体类型变量* 不需要在前面添加 struct 关键字*/
typedef struct Student
{// 声明变量时 , 会自动分配这 5 字节内存// 赋值时 , 可以直接使用 = 赋值字符串char name[5];int age;int id;// 声明变量时 , 只会为 4 字节指针分配内存// 具体的 字符串内存 需要额外使用 malloc 申请内存// 赋值时 , 必须使用 strcpy 函数 , 向堆内存赋值char *address;// 学生小组成员 , 由多个字符串组成// 二级指针 , 指向多个 一级指针// 每个 一级指针 指向 一个字符串// 此处的 二级指针 可以使用 指针数组 / 二维数组 / 自定义二级指针内存// 此处选择的模型是 自定义二级指针内存char **team;
}Student;/*** @brief printf_struct_array 打印结构体数组* @param array 数组作为函数参数退化为指针* @param count 数组中的元素个数*/
void printf_struct_array(Student *array, int count)
{// 循环控制变量int i = 0;// 验证数组合法性if(array == NULL){return;}// 打印结构体数组中的 结构体 age 字段for(i = 0; i < count; i++){printf("Student age = %d\n", array[i].age);}
}/*** @brief sort_struct_array 对结构体数组 按照年龄进行排序* @param array 结构体指针* @param count 结构体数组的元素个数*/
void sort_struct_array(Student *array, int count)
{// 循环控制变量int i = 0, j = 0;// 学生年龄Student tmp;// 验证数组合法性if(array == NULL){return;}// 排序for(i = 0; i < count; i++){for(j = i + 1; j < count; j++){if(array[i].age > array[j].age){tmp = array[i];array[i] = array[j];array[j] = tmp;}}}
}/*** @brief create_student 堆内存中分配内存* 为二级指针成员分配内存时 , 先为二级指针分配内存 , 再为一级指针分配内存* @param array 二级指针 , 指向结构体数组* @return*/
int create_student(Student **array, int count)
{// 返回值int ret = 0;// 循环控制变量int i = 0, j = 0;// 临时变量Student *tmp = NULL;// 验证二级指针合法性if(array == NULL){ret = -1;return ret;}// 堆内存中申请内存tmp = (Student *)malloc(sizeof(Student) * count);// 初始化分配的内存memset(tmp, 0, sizeof(Student) * count);// 为每个结构体的 address 成员分配内存for(i = 0; i < count; i++){// 为一级指针分配内存模型tmp[i].address = (char *)malloc(20);// 为 二级指针 内存模型分配内存 , 分配 3 个 一级指针 变量内存char **p = (char **)malloc(3 * sizeof(char *));// 为 二级指针 指向的 一级指针 分配内存for(j = 0; j < 3; j++){// 每个一级指针分配 10 字节数据p[j] = (char *)malloc(10 * sizeof(char));}// 将分配好内存的 二级指针 模型 , 赋值给结构体中的二级指针tmp[i].team = p;}// 通过间接赋值 设置返回值*array = tmp;return ret;
}/*** @brief free_student 释放内存* 释放内存时 , 先释放 二级指针 指向的 一级指针 的内存 , 再释放 二级指针 内存* @param array* @return*/
int free_student(Student **array, int count)
{// 返回值int ret = 0;// 循环控制变量int i = 0, j = 0;// 验证二级指针合法性if(array == NULL){ret = -1;return ret;}// 释放 每个结构体的 address 成员分配内存for(i = 0; i < count; i++){// 释放一级指针free((*array)[i].address);(*array)[i].address = NULL;// 释放二级指针指向的一级指针for(j = 0; j < 3; j++){if((*array)[i].team[j] != NULL){free( (*array)[i].team[j] );(*array)[i].team[j] = NULL;}}// 释放二级指针if((*array)[i].team != NULL){free( (*array)[i].team );(*array)[i].team = NULL;}}// 释放 结构体内存free(*array);// 指针置空 , 防止野指针*array = NULL;return ret;
}/*** @brief 主函数入口* @return*/
int main(int argc, char* argv[], char**env)
{// 声明结构体数组 , 该数组在栈内存中Student *array = NULL;// 循环控制变量int i = 0;// 堆内存中为结构体指针分配内存create_student(&array, 2);// 命令行中 , 接收输入的年龄for(i = 0; i < 2; i++){// 命令换行中 接收 输入的年龄 ,// 设置到 Student 数组元素的 age 成员中printf("\n Input Age :\n");scanf("%d", &(array[i].age));printf("\n Input ID :\n");scanf("%d", &(array[i].id));printf("\n Input Name :\n");scanf("%s", array[i].name);printf("\n Input Address :\n");scanf("%s", array[i].address);printf("\n Input Team 1 Name :\n");scanf("%s", array[i].team[0]);printf("\n Input Team 2 Name :\n");scanf("%s", array[i].team[1]);printf("\n Input Team 3 Name :\n");scanf("%s", array[i].team[2]);}// 结构体数组 按照 age 排序sort_struct_array(array, 2);// 打印结构体数组中的 结构体 age 字段printf_struct_array(array, 2);// 释放堆内存数据free_student(&array, 2);// 命令行不要退出system("pause");return 0;
}

执行结果 :

Input Age :
18Input ID :
1Input Name :
TomInput Address :
CHinaInput Team 1 Name :
Tom1Input Team 2 Name :
Tom2Input Team 3 Name :
Tom3Input Age :
16Input ID :
2Input Name :
JerryInput Address :
BeijingInput Team 1 Name :
Jerry1Input Team 2 Name :
Jerry2Input Team 3 Name :
Jerry3
Student age = 16
Student age = 18
请按任意键继续. . .

【C 语言】结构体 ( 结构体中嵌套二级指针 | 为 结构体内的二级指针成员 分配内存 | 释放 结构体内的二级指针成员 内存 )相关推荐

  1. 【C 语言】结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )

    文章目录 一.结构体中嵌套一级指针 1.声明 结构体类型 2.为 结构体 变量分配内存 ( 分配内存时先 为结构体分配内存 然后再为指针分配内存 ) 3.释放结构体内存 ( 释放内存时先释放 指针成员 ...

  2. MySQL:如何将树形结构存储在数据库中

    文章目录 问题 方案一 Adjacency List(存储父节点) 数据库存储结构 SQL示例 1.添加节点 2.查询小天的直接上司 3.查询老宋管理下的直属员工 4.查询小天的所有上司 5.查询老王 ...

  3. C语言试题五十二之学生的记录由学号和成绩组称个,n名大学生得数据已在主函数中放入结构体数组a中,请编写函数fun,它的功能时:按分数的高低排列学生的记录,高分在前。

    1. 题目 请编写一个函数void function(Student a[], int n),其功能时:学生的记录由学号和成绩组称个,n名大学生得数据已在主函数中放入结构体数组a中,请编写函数fun, ...

  4. C语言:指针的偏移步长、结构体成员的偏移量、嵌套结构体成员的偏移量、结构体的内存对齐

    文章目录 1 不同类型指针的偏移步长 2 结构体成员的偏移量 3 嵌套结构体成员的偏移量 4 结构体的内存对齐 4.1 内存对齐的原因与优点 4.2 结构体内存对齐的规则 4.3 结构体嵌套结构体时的 ...

  5. C语言结构体与C++中结构体和类的区别

    在C++中除了类中可以有构造函数和析构函数外,结构体中也可以包含构造函数和析构函数,这是因为结构体和类基本雷同,唯一区别是,类中成员变量默认为私有,而结构体中则为公有.注意,C++中的结构体是可以有析 ...

  6. c语言 由函数组成的数组,学生的记录由学号和成绩组成,N名学生的数据已在主函数中放入结构体数组s中,请编写函数fun(),它的_考题宝...

    学生的记录由学号和成绩组成,N名学生的数据已在主函数中放入结构体数组s中,请编写函数fun(),它的功能是按分数的高低排列学生的记录,低分在前. 注意:部分源程序给出如下. 请勿改动主函数main和其 ...

  7. c语言结构体共用体枚举实例程序,10-C语言结构体-共用体-枚举

    结构体是什么? 结构体和数组一样属于构造类型 数组是用于保存一组相同类型数据的,而结构体是用于保存一组不同类型的数组 定义结构体 在使用结构体之前必须先定义结构体类型,因为C语言不知道你的结构体中需要 ...

  8. c语言指针变量输出不了共用体,瘋子C语言札记(结构体/共用体/枚举篇)

    瘋子C语言笔记(结构体/共用体/枚举篇) (一)结构体类型 1.简介: 例: struct date { int month; int day; int year; }; struct student ...

  9. golang 结构体断言_Golang中的reflect原理

    反射(reflect)是在计算机程序运行时,访问,检查,修改它自身的一种能力,是元编程的一种形式.在Java等语言中都很好地支持了反射.Golang也实现了反射,主要核心位于reflect包,官方文档 ...

最新文章

  1. 3.请执行命令取出linux中eth0的IP地址(考试题答案系列)
  2. php记录用户搜索历史记录,PHPCookei记录用户历史浏览信息的代码
  3. 微信小程序配置WSS协议
  4. ajax使用html()后样式无效,jquery.ajax使用字符串拼接后内联css样式失效
  5. Redis集群一致性Hash效果的代码演示
  6. 关于myBatis的问题There is no getter for property named 'USER_NAME' in 'class com.bky.model.实例类'
  7. Instant Complexity--POJ 1472
  8. Vue组件学习之组件自定义事件
  9. python重新启动整个脚本_每次对脚本进行更改时,都需要在终端中重新启动python...
  10. 超有趣的灵魂都在看什么?
  11. 运行c语言程序显示已停止运行程序,c – “此应用程序已请求运行时以不寻常的方式终止它.”...
  12. 借助Sci-Hub免费下载外文文献
  13. 企业固定资产管理存在的问题及改进建议
  14. mysql 保留两位小数 --round
  15. ObjectARX反应器概述
  16. mysql pdo 端口_链接Mysql的api mysqli和pdo
  17. PySpark RDD操作
  18. python qrcode 二维码中间贴图彩色
  19. xslt简介_XSLT简介
  20. 单片机:STC89C52的最小单元

热门文章

  1. Hadoop权威指南阅读笔记
  2. Java课程03总结
  3. Word 最后一页无法删除-解决办法
  4. Java学习个人备忘录之线程间的通信
  5. 探索Oracle之数据库升级八 12c Downgrade 11gR2
  6. Android 透明度百分比对应的 十六进制
  7. Intelij IDEA 2016.3安装mybatis插件并激活教程
  8. javaweb回顾第十二篇监听器
  9. 记asp.net VB与C# 页面参数传值
  10. 算法学习:主席树(可持久化线段树)