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

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

文章目录

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

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 :
18
 Input ID :
1
 Input Name :
Tom
 Input Address :
CHina
 Input Team 1 Name :
Tom1
 Input Team 2 Name :
Tom2
 Input Team 3 Name :
Tom3
 Input Age :
16
 Input ID :
2
 Input Name :
Jerry
 Input Address :
Beijing
 Input Team 1 Name :
Jerry1
 Input Team 2 Name :
Jerry2
 Input Team 3 Name :
Jerry3
Student age = 16
Student age = 18
请按任意键继续. . .

image.png

目录
打赏
0
0
0
0
40
分享
相关文章
【C语言程序设计——选择结构程序设计】预测你的身高(头歌实践教学平台习题)【合集】
分支的语句,这可能不是预期的行为,这种现象被称为“case穿透”,在某些特定情况下可以利用这一特性来简化代码,但在大多数情况下,需要谨慎使用。编写一个程序,该程序需输入个人数据,进而预测其成年后的身高。根据提示,在右侧编辑器补充代码,计算并输出最终预测的身高。分支下的语句,提示用户输入无效。常量的值必须是唯一的,且在同一个。语句的作用至关重要,如果遗漏。开始你的任务吧,祝你成功!,程序将会继续执行下一个。常量都不匹配,就会执行。来确保程序的正确性。
227 10
|
7月前
|
【C语言程序设计——基础】顺序结构程序设计(头歌实践教学平台习题)【合集】
目录 任务描述 相关知识 编程要求 测试说明 我的通关代码: 测试结果: 任务描述 相关知识 编程编写一个程序,从键盘输入3个变量的值,例如a=5,b=6,c=7,然后将3个变量的值进行交换,使得a=6,b=7,c=5。面积=sqrt(s(s−a)(s−b)(s−c)),s=(a+b+c)/2。使用输入函数获取半径,格式指示符与数据类型一致,实验一下,不一致会如何。根据提示,在右侧编辑器补充代码,计算并输出圆的周长和面积。
143 10
【C语言程序设计——选择结构程序设计】求一元二次方程的根(头歌实践教学平台习题)【合集】
本任务要求根据求根公式计算并输出一元二次方程的两个实根,精确到小数点后两位。若方程无实根,则输出提示信息。主要内容包括: - **任务描述**:使用求根公式计算一元二次方程的实根。 - **相关知识**:掌握 `sqrt()` 函数的基本使用方法,判断方程是否有实根。 - **编程要求**:根据输入的系数,计算并输出方程的根或提示无实根。 - **测试说明**:提供两组测试数据及预期输出,确保代码正确性。 - **通关代码**:包含完整的 C 语言代码示例,实现上述功能。 通过本任务,你将学会如何处理一元二次方程的求解问题,并熟悉 `sqrt()` 函数的使用。
117 5
【C语言程序设计——选择结构程序设计】按从小到大排序三个数(头歌实践教学平台习题)【合集】
本任务要求从键盘输入三个数,并按从小到大的顺序排序后输出。主要内容包括: - **任务描述**:实现三个数的排序并输出。 - **编程要求**:根据提示在编辑器中补充代码。 - **相关知识**: - 选择结构(if、if-else、switch) - 主要语句类型(条件语句) - 比较操作与交换操作 - **测试说明**:提供两组测试数据及预期输出。 - **通关代码**:完整代码示例。 - **测试结果**:展示测试通过的结果。 通过本任务,你将掌握基本的选择结构和排序算法的应用。祝你成功!
97 4
【C语言程序设计——选择结构程序设计】求阶跃函数的值(头歌实践教学平台习题)【合集】
本任务要求输入x的值,计算并输出特定阶跃函数的结果。主要内容包括: 1. **选择结构基本概念**:介绍if、if-else、switch语句。 2. **主要语句类型**:详细解释if、if-else、switch语句的使用方法。 3. **跃迁函数中变量的取值范围**:说明如何根据条件判断变量范围。 4. **计算阶跃函数的值**:通过示例展示如何根据给定条件计算函数值。 编程要求:在右侧编辑器Begin-End之间补充代码,实现阶跃函数的计算和输出。测试说明提供了多个输入及其预期输出,确保代码正确性。最后提供通关代码和测试结果,帮助理解整个过程。
98 0
【C语言程序设计——选择结构程序设计】判断一个数是不是5和7的倍数(头歌实践教学平台习题)【合集】
本任务要求输入一个正整数,判断其是否同时是5和7的倍数,若是输出&quot;Yes&quot;,否则输出&quot;No&quot;。内容涵盖选择结构的基本概念、主要语句类型(if、if-else、switch)及条件判断逻辑,帮助理解编程中的分支执行与条件表达式。测试用例包括正数、负数及非倍数情况,确保代码逻辑严谨。通关代码示例如下: ```cpp #include &quot;stdio.h&quot; int main(){ int a; scanf(&quot;%d&quot;, &a); if (a &lt;= 0){ printf(&quo
237 0
【C语言程序设计——选择结构程序设计】求输入的日期是该年的第几天(头歌实践教学平台习题)【合集】
本任务要求编写程序,根据用户输入的年月日(以空格或回车分隔),计算并输出该天是该年的第几天,需注意判断闰年。主要内容包括: 1. **任务描述**:实现从键盘输入年月日,计算该天是当年的第几天。 2. **相关知识**: - `switch` 结构的基本语法及使用注意事项。 - 判断闰年的条件:能被4整除但不能被100整除,或能被400整除的年份为闰年。 3. **编程要求**:根据提示补充代码,确保程序正确处理输入并输出结果。 4. **测试说 示例代码展示了如何使用 `switch` 语句和闰年判断逻辑来完成任务。通过此练习,掌握 `switch` 语句的应用及闰年判断方法。
217 0
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
737 13
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
265 12
|
27天前
|
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
218 15
下一篇
BFE 初探
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问