结构体中指针赋值问题的分析及C代码示例

问题描述
某结构体的定义如下:

typedef struct
{
    int     iAge;                // 年龄
    char    szAddr1[100];        // 地址1
    char   *pszAddr2;            // 地址2
    char  **pszAddr3;            // 地址3
} T_PeopleInfo;

请问如何对结构体中的各个成员变量(尤其是指针变量)进行赋值?

问题分析及C代码示例
我们可以看到,在结构体T_PeopleInfo中,pszAddr2和pszAddr3均为指针,其中pszAddr2为一级指针,pszAddr3为二级指针。本文的重点,就是要找到对一级指针和二级指针赋值的正确方法。

我们把结构体T_PeopleInfo放到具体的C代码中,以直观地展现对结构体中的各个成员变量的赋值方法。

我们首先编写如下程序(程序1):

/**********************************************************************
* 版权所有 (C)2016, Zhou Zhaoxiong。
*
* 文件名称:PointerTest.c
* 文件标识:无
* 内容摘要:演示指针的用法
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160712
*
**********************************************************************/
#include <stdio.h>


// 重定义数据类型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef unsigned char       UINT8;

// 结构体定义
typedef struct
{
    UINT32   iAge;                    // 年龄
    UINT8    szAddr1[100];            // 地址1
    UINT8   *pszAddr2;                // 地址2
    UINT8  **pszAddr3;                // 地址3
} T_PeopleInfo;


/****************************************************************
* 功能描述: 主函数
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 0-执行完成
* 其他说明: 无
* 修改日期       版本号        修改人        修改内容
* -------------------------------------------------------------
* 20160712        V1.0     Zhou Zhaoxiong     创建
****************************************************************/
INT32 main(void)
{
    T_PeopleInfo tPeopleInfo = {0};

    // 结构体变量赋值
    // 对iAge赋值
    tPeopleInfo.iAge = 10;

    // 对szAddr1赋值
    strncpy(tPeopleInfo.szAddr1, "Chongqing, China!", strlen("Chongqing, China!"));

    // 对pszAddr2赋值
    strncpy(tPeopleInfo.pszAddr2, "Chengdu, China!", strlen("Chengdu, China!"));

    // 对pszAddr3赋值
    strncpy(tPeopleInfo.pszAddr3, "Wuhan, China!", strlen("Wuhan, China!"));

    // 打印变量的值
    printf("Age=%d, Addr1=%s, Addr2=%s, Addr3=%s", tPeopleInfo.iAge, tPeopleInfo.szAddr1, tPeopleInfo.pszAddr2, tPeopleInfo.pszAddr3);

    return 0;
}

在程序1中,我们按照对结构体中的数组的赋值方法对指针赋值,程序可以编译通过,但运行的时候,程序便会挂掉。究其原因,是因为没有为pszAddr2和pszAddr3指针分配内存空间。

我们对程序1进行改进,编写出以下程序(程序2):

/**********************************************************************
* 版权所有 (C)2016, Zhou Zhaoxiong。
*
* 文件名称:PointerTest.c
* 文件标识:无
* 内容摘要:演示指针的用法
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160712
*
**********************************************************************/
#include <stdio.h>


// 重定义数据类型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef signed   char       INT8;

// 结构体定义
typedef struct
{
    UINT32   iAge;                    // 年龄
    INT8     szAddr1[100];            // 地址1
    INT8    *pszAddr2;                // 地址2
    INT8   **pszAddr3;                // 地址3
} T_PeopleInfo;


/****************************************************************
* 功能描述: 主函数
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 0-执行完成
* 其他说明: 无
* 修改日期       版本号        修改人        修改内容
* -------------------------------------------------------------
* 20160712        V1.0     Zhou Zhaoxiong     创建
****************************************************************/
INT32 main(void)
{
    T_PeopleInfo tPeopleInfo = {0};

    // 结构体变量赋值
    // 对iAge赋值
    tPeopleInfo.iAge = 10;

    // 对szAddr1赋值
    strncpy(tPeopleInfo.szAddr1, "Chongqing, China!", strlen("Chongqing, China!"));

    // 对pszAddr2赋值
    tPeopleInfo.pszAddr2 = (INT8 *)malloc(100);
    if (tPeopleInfo.pszAddr2 == NULL)
    {
        return -1;
    }
    strncpy(tPeopleInfo.pszAddr2, "Chengdu, China!", strlen("Chengdu, China!"));

    // 对pszAddr3赋值
    tPeopleInfo.pszAddr3 = (INT8 *)malloc(100);
    if (tPeopleInfo.pszAddr3 == NULL)
    {
        return -2;
    }
    strncpy(tPeopleInfo.pszAddr3, "Wuhan, China!", strlen("Wuhan, China!"));

    // 打印变量的值
    printf("Age=%d, Addr1=%s, Addr2=%s, Addr3=%s\n", tPeopleInfo.iAge, tPeopleInfo.szAddr1, tPeopleInfo.pszAddr2, tPeopleInfo.pszAddr3);

    return 0;
}

在程序2中,我们先使用malloc为pszAddr2和pszAddr3分配了内存空间(注意,执行malloc之后,要判断指针是否为空),此时就可以将变量值赋给它们。程序编译和运行都是正常的,输出结果如下:

~/zhouzx/Test/PointerTest> PointerTest
Age=10, Addr1=Chongqing, China!, Addr2=Chengdu, China!, Addr3=Wuhan, China!

除了程序2可以实现对一级指针和二级指针的正常赋值之外,我们还可以编写如下程序(程序3):

/**********************************************************************
* 版权所有 (C)2016, Zhou Zhaoxiong。
*
* 文件名称:PointerTest.c
* 文件标识:无
* 内容摘要:演示指针的用法
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160712
*
**********************************************************************/
#include <stdio.h>


// 重定义数据类型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef signed   char       INT8;

// 结构体定义
typedef struct
{
    UINT32   iAge;                    // 年龄
    INT8     szAddr1[100];            // 地址1
    INT8    *pszAddr2;                // 地址2
    INT8   **pszAddr3;                // 地址3
} T_PeopleInfo;


/****************************************************************
* 功能描述: 主函数
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 0-执行完成
* 其他说明: 无
* 修改日期       版本号        修改人        修改内容
* -------------------------------------------------------------
* 20160712        V1.0     Zhou Zhaoxiong     创建
****************************************************************/
INT32 main(void)
{
    T_PeopleInfo tPeopleInfo = {0};

    // 结构体变量赋值
    // 对iAge赋值
    tPeopleInfo.iAge = 10;

    // 对szAddr1赋值
    strncpy(tPeopleInfo.szAddr1, "Chongqing, China!", strlen("Chongqing, China!"));

    // 对pszAddr2赋值
    tPeopleInfo.pszAddr2 = "Chengdu, China!";

    // 对pszAddr3赋值
    tPeopleInfo.pszAddr3 = "Wuhan, China!";

    // 打印变量的值
    printf("Age=%d, Addr1=%s, Addr2=%s, Addr3=%s\n", tPeopleInfo.iAge, tPeopleInfo.szAddr1, tPeopleInfo.pszAddr2, tPeopleInfo.pszAddr3);

    return 0;
}

在程序3中,我们直接将字符串赋给了pszAddr2和pszAddr3,也就是将这两个字符串的首地址赋给了指针。那么,指针所指向的地址中存放的内容就是字符串的值。程序编译和运行都是正常的,输出结果如下:

~/zhouzx/Test/PointerTest> PointerTest
Age=10, Addr1=Chongqing, China!, Addr2=Chengdu, China!, Addr3=Wuhan, China!

另,对于二级指针的赋值,我们还可以编写如下程序(程序4):

/**********************************************************************
* 版权所有 (C)2016, Zhou Zhaoxiong。
*
* 文件名称:PointerTest.c
* 文件标识:无
* 内容摘要:演示指针的用法
* 其它说明:无
* 当前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160712
*
**********************************************************************/
#include <stdio.h>


// 重定义数据类型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef signed   char       INT8;

// 结构体定义
typedef struct
{
    UINT32   iAge;                    // 年龄
    INT8     szAddr1[100];            // 地址1
    INT8    *pszAddr2;                // 地址2
    INT8   **pszAddr3;                // 地址3
} T_PeopleInfo;


/****************************************************************
* 功能描述: 主函数
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 0-执行完成
* 其他说明: 无
* 修改日期       版本号        修改人        修改内容
* -------------------------------------------------------------
* 20160712        V1.0     Zhou Zhaoxiong     创建
****************************************************************/
INT32 main(void)
{
    T_PeopleInfo tPeopleInfo = {0};

    // 结构体变量赋值
    // 对iAge赋值
    tPeopleInfo.iAge = 10;

    // 对szAddr1赋值
    strncpy(tPeopleInfo.szAddr1, "Chongqing, China!", strlen("Chongqing, China!"));

    // 对pszAddr2赋值
    tPeopleInfo.pszAddr2 = "Chengdu, China!";

    // 对pszAddr3赋值
    tPeopleInfo.pszAddr3 = (INT8 *)malloc(100);
    if (tPeopleInfo.pszAddr3 == NULL)
    {
        return -1;
    }
    *(tPeopleInfo.pszAddr3) = "Wuhan, China!";

    // 打印变量的值
    printf("Age=%d, Addr1=%s, Addr2=%s, Addr3=%s\n", tPeopleInfo.iAge, tPeopleInfo.szAddr1, tPeopleInfo.pszAddr2, *(tPeopleInfo.pszAddr3));

    return 0;
}

在程序4中,我们先用malloc为pszAddr3分配了内存空间,然后便可以使用该指针来接收字符串变量的值(注意,这里是将“Wuhan, China!”赋给了*(tPeopleInfo.pszAddr3))。程序编译和运行都是正常的,输出结果如下:

~/zhouzx/Test/PointerTest> PointerTest
Age=10, Addr1=Chongqing, China!, Addr2=Chengdu, China!, Addr3=Wuhan, China!

总结
本文对结构体中指针赋值问题进行了分析,并用C代码演示了指针的赋值方法。

在实际的C语言项目中,很多程序出现问题,就是对指针的处理不当造成的。因此,熟练掌握各种指针的使用方法,是对一个合格的软件开发人员的基本要求。

  • 8
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
C++智能指针 智能指针_unique_ptr智能指针详解 智能指针详解 作为智能指针的⼀种,unique_ptr 指针⾃然也具备"在适当时机⾃动释放堆内存空间"的能⼒。和 shared_ptr 指针最⼤的不同之处在 于,unique_ptr 指针指向的堆内存⽆法同其它 unique_ptr 共享,也就是说,每个 unique_ptr 指针都独⾃拥有对其所指堆内存空间的所有 权。 这也就意味着,每个 unique_ptr 指针指向的堆内存空间的引⽤计数,都只能为 1,⼀旦该 unique_ptr 指针放弃对所指堆内存空 间的所有权,则该空间会被⽴即释放回收。 unique_ptr 智能指针是以模板类的形式提供的,unique_ptr<T>(T 为指针所指数据的类型)定义在<memory>头⽂件,并位于 std 命名空间 。因此,要想使⽤ unique_ptr 类型指针,程序应⾸先包含如下 2 条语句: 1. #include <memory> 2. using namespace std; 第 2 句并不是必须的,可以不添加,则后续在使⽤ unique_ptr 指针时,必须标注std:: 。 unique_ptr智能指针的创建 智能指针的创建 考虑到不同实际场景的需要,unique_ptr<T> 模板类提供了多个实⽤的构造函数,这⾥给读者列举了⼏种常⽤的构造 unique_ptr 智能指针的⽅式。 1) 通过以下 2 种⽅式,可以创建出空的 unique_ptr 指针: 1. std::unique_ptr<int> p1(); 2. std::unique_ptr<int> p2(nullptr); 2) 创建 unique_ptr 指针的同时,也可以明确其指向。例如: 1. std::unique_ptr<int> p3(new int); 由此就创建出了⼀个 p3 智能指针,其指向的是可容纳 1 个整数的堆存储空间。 和可以⽤ make_shared<T>() 模板函数初始化 shared_ptr 指针不同,C++11 标准并没有为 unique_ptr 类型指针添 加类似的模板函数。 3) 基于 unique_ptr 类型指针不共享各⾃拥有的堆内存,因此 C++11 标准的 unique_ptr 模板类没有提供拷贝构造函数,只提供 了移动构造函数。例如: 1. std::unique_ptr<int> p4(new int); 2. std::unique_ptr<int> p5(p4);//错误,堆内存不共享 3. std::unique_ptr<int> p5(std::move(p4));//正确,调⽤移动构造函数 值得⼀提的是,对于调⽤移动构造函数的 p4 和 p5 来说,p5 将获取 p4 所指堆空间的所有权,⽽ p4 将变成空指针(nullptr)。 4) 默认情况下,unique_ptr 指针采⽤ std::default_delete<T> ⽅法释放堆内存。当然,我们也可以⾃定义符合实际场景的释放规 则。值得⼀提的是,和 shared_ptr 指针不同,为 unique_ptr ⾃定义释放规则,只能采⽤函数对象的⽅式。例如: 1. //⾃定义的释放规则 2. struct myDel 3. { 4. void operator()(int *p) { 5. delete p; 6. } 7. }; 8. std::unique_ptr<int, myDel> p6(new int); 9. //std::unique_ptr<int, myDel> p6(new int, myDel()); unique_ptr<T>模板类提供的成员⽅法 模板类提供的成员⽅法 为了⽅便⽤户使⽤ unique_ptr 智能指针,unique_ptr<T> 模板类还提供有⼀些实⽤的成员⽅法,它们各⾃的功能如表 1 所⽰。 表 1 unique_ptr指针可调⽤的成员函数 成员函数名 成员函数名 功 功 能 能 operator*() 获取当前 unique_ptr 指针指向的数据。 operator->() 重载 -> 号,当智能指针指向的数据类型为⾃定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。 operator =() 重载了 = 赋值号,从⽽可以将 nullptr 或者⼀个右值 unique_ptr 指针直接赋值给当前同类型的 unique_ptr 指针。 operator []() 重载了 [] 运算符,当 unique_ptr 指针指向⼀个数组时,可以直接通过 [] 获取指定下标位置处的数据。 get() 获取当前 unique_ptr 指针内部包含的普通指针。 get_deleter()
结合视频效果更好 https://www.bilibili.com/video/av81167448?p=189 1. 初识Go语言 1 1.1 Go语言介绍 1 1.1.1 Go语言是什么 1 1.1.2 Go语言优势 1 1.1.3 Go适合用来做什么 2 1.2 环境搭建 2 1.2.1 安装和设置 2 1.2.2 标准命令概述 2 1.2.3 学习资料 3 1.3 第一个Go程序 3 1.3.1 Hello Go 3 1.3.2 代码分析 3 1.3.3 命令行运行程序 4 2. 基础类型 4 2.1 命名 4 2.2 变量 5 2.2.1 变量声明 5 2.2.2 变量初始化 6 2.2.3 变量赋值 6 2.2.4 匿名变量 6 2.3 常量 7 2.3.1 字面常量(常量值) 7 2.3.2 常量定义 8 2.3.3 iota枚举 8 2.4 基础数据类型 10 2.4.1 分类 10 2.4.2 布尔类型 11 2.4.3 整型 11 2.4.4 浮点型 11 2.4.5 字符类型 11 2.4.6 字符串 12 2.4.7 复数类型 12 2.5 fmt包的格式化输出输入 13 2.5.1 格式说明 13 2.5.2 输出 14 2.5.3 输人 14 2.6 类型转换 15 2.7 类型别名 15 3. 运算符 15 3.1 算术运算符 15 3.2 关系运算符 16 3.3 逻辑运算符 16 3.4 位运算符 16 3.5 赋值运算符 17 3.6 其他运算符 17 3.7 运算符优先级 17 4. 流程控制 18 4.1 选择结构 18 4.1.1 if语句 18 4.1.2 switch语句 19 4.2 循环语句 20 4.2.1 for 20 4.2.2 range 20 4.3 跳转语句 21 4.3.1 break和continue 21 4.3.2 goto 21 5. 函数 22 5.1 定义格式 22 5.2 自定义函数 22 5.2.1 无参无返回值 22 5.2.2 有参无返回值 23 5.2.3 无参有返回值 24 5.2.4 有参有返回值 25 5.3 递归函数 26 5.4 函数类型 27 5.5 匿名函数与闭包 27 5.6 延迟调用defer 30 5.6.1 defer作用 30 5.6.2 多个defer执行顺序 30 5.6.3 defer和匿名函数结合使用 31 5.7 获取命令行参数 31 5.8 作用域 32 5.8.1 局部变量 32 5.8.2 全局变量 33 5.8.3 不同作用域同名变量 33 6. 工程管理 34 6.1 工作区 34 6.1.1 工作区介绍 34 6.1.2 GOPATH设置 35 6.2 包 35 6.2.1 自定义包 35 6.2.2 main包 36 6.2.3 main函数和init函数 36 6.2.4 导入包 38 6.3 测试案例 40 6.3.1 测试代码 40 6.3.2 GOPATH设置 42 6.3.3 编译运行程序 43 6.3.4 go install的使用 43 7. 复合类型 45 7.1 分类 45 7.2 指针 45 7.2.1 基本操作 45 7.2.2 new函数 46 7.2.3 指针做函数参数 46 7.3 数组 47 7.3.1 概述 47 7.3.2 操作数组 47 7.3.3 在函数间传递数组 48 7.4 slice 49 7.4.1 概述 49 7.4.2 切片的创建和初始化 49 7.4.3 切片的操作 50 7.4.4 切片做函数参数 52 7.5 map 53 7.5.1 概述 53 7.5.2 创建和初始化 53 7.5.3 常用操作 54 7.5.4 map做函数参数 55 7.6 结构体 56 7.6.1 结构体类型 56 7.6.2 结构体初始化 57 7.6.3 结构体成员的使用 57 7.6.4 结构体比较 58 7.6.5 结构体作为函数参数 59 7.6.6 可见性 59 8. 面向对象编程 61 8.1 概述 61 8.2 匿名组合 61 8.2.1 匿名字段 61 8.2.2 初始化 62 8.2.3 成员的操作 62 8.2.4 同名字段 63 8.2.5 其它匿名字段 64 8.3 方法 65 8.3.1 概述 65 8.3.2 为类型添加方法 66 8.3.3 值语义和引用语义 67 8.3.4
C++11unique_ptr智能指针详解 智能指针详解 在《》的基础上,本节继续讲解 C++11 标准提供的另⼀种智能指针,即 unique_ptr 智能指针。 作为智能指针的⼀种,unique_ptr 指针⾃然也具备"在适当时机⾃动释放堆内存空间"的能⼒。和 shared_ptr 指针最⼤的不同之处在 于,unique_ptr 指针指向的堆内存⽆法同其它 unique_ptr 共享,也就是说,每个 unique_ptr 指针都独⾃拥有对其所指堆内存空间的所有 权。 这也就意味着,每个 unique_ptr 指针指向的堆内存空间的引⽤计数,都只能为 1,⼀旦该 unique_ptr 指针放弃对所指堆内存空 间的所有权,则该空间会被⽴即释放回收。 unique_ptr 智能指针是以模板类的形式提供的,unique_ptr<T>(T 为指针所指数据的类型)定义在<memory>头⽂件,并位于 std 命名空间 。因此,要想使⽤ unique_ptr 类型指针,程序应⾸先包含如下 2 条语句: 1. #include <memory> 2. using namespace std; 第 2 句并不是必须的,可以不添加,则后续在使⽤ unique_ptr 指针时,必须标注std::。 unique_ptr智能指针的创建 智能指针的创建 考虑到不同实际场景的需要,unique_ptr<T> 模板类提供了多个实⽤的构造函数,这⾥给读者列举了⼏种常⽤的构造 unique_ptr 智能指针的 ⽅式。 1) 通过以下 2 种⽅式,可以创建出空的 unique_ptr 指针: 1. std::unique_ptr<int> p1(); 2. std::unique_ptr<int> p2(nullptr); 2) 创建 unique_ptr 指针的同时,也可以明确其指向。例如: 1. std::unique_ptr<int> p3(new int); 由此就创建出了⼀个 p3 智能指针,其指向的是可容纳 1 个整数的堆存储空间。 和可以⽤ make_shared<T>() 模板函数初始化 shared_ptr 指针不同,C++11 标准并没有为 unique_ptr 类型指针添加类似的模 板函数。 3) 基于 unique_ptr 类型指针不共享各⾃拥有的堆内存,因此 C++11 标准的 unique_ptr 模板类没有提供拷贝构造函数,只提供了移动构造 函数。例如: 1. std::unique_ptr<int> p4(new int); 2. std::unique_ptr<int> p5(p4);//错误,堆内存不共享 3. std::unique_ptr<int> p5(std::move(p4));//正确,调⽤移动构造函数 值得⼀提的是,对于调⽤移动构造函数的 p4 和 p5 来说,p5 将获取 p4 所指堆空间的所有权,⽽ p4 将变成空指针(nullptr)。 4) 默认情况下,unique_ptr 指针采⽤ std::default_delete<T> ⽅法释放堆内存。当然,我们也可以⾃定义符合实际场景的释放规则。值得⼀ 提的是,和 shared_ptr 指针不同,为 unique_ptr ⾃定义释放规则,只能采⽤函数对象的⽅式。例如: 1. //⾃定义的释放规则 2. struct myDel 3. { 4. void operator()(int *p) { 5. delete p; 6. } 7. }; 8. std::unique_ptr<int, myDel> p6(new int); 9. //std::unique_ptr<int, myDel> p6(new int, myDel()); unique_ptr<T>模板类提供的成员⽅法 模板类提供的成员⽅法 为了⽅便⽤户使⽤ unique_ptr 智能指针,unique_ptr<T> 模板类还提供有⼀些实⽤的成员⽅法,它们各⾃的功能如表 1 所⽰。 表 1 unique_ptr指针可调⽤的成员函数 成员函数名 成员函数名 功 功 能 能 operator*() 获取当前 unique_ptr 指针指向的数据。 operator->() 重载 -> 号,当智能指针指向的数据类型为⾃定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。 operator =() 重载了 = 赋值号,从⽽可以将 nullptr 或者⼀个右值 unique_ptr 指针直接赋值给当前同类型的 unique_ptr 指针。 operator []() 重载了 [] 运算符,当 unique_ptr 指针指向⼀个数组时,可以直接通过 [] 获取指定下标位置处的数据。 get(

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周兆熊-IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值