C语言中结构体参数变量的传递

简介: 【文章摘要】       在C语言中,结构体参数变量经常作为函数的参数来进行传递。但如果参数设置不当,会出现内存问题。       本文以实际的程序代码为例,详细地介绍如何正确地使用结构体参数变量,为相关的开发工作提供了参考。

【文章摘要

       在C语言中,结构体参数变量经常作为函数的参数来进行传递。但如果参数设置不当,会出现内存问题。

       本文以实际的程序代码为例,详细地介绍如何正确地使用结构体参数变量,为相关的开发工作提供了参考。

【关键词

       C语言  结构体  函数  参数  传递

 

一、前言

       本文中的程序实现对员工信息结构体字段赋值并打印出来的功能。该结构体的定义如下:

// 员工信息结构体

typedef struct

{

       INT8       szEmployeeName[100];     // 员工姓名

       UINT16  iEmployeeAge;                    // 员工年龄

       UINT32  iEmployeeNo;                      // 员工工号

} TEmployeeInfo;

 

        函数GetEmployeeInfo用来对员工信息字段进行赋值,其声明如下:

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo);

 

       在主函数main中,采用两种参数传递的方法,一种是指针传递,另一种是非指针传递

 

二、采用指针传递时的程序代码

       采用指针传递时的程序代码如下:

/**********************************************************************

* 版权所有 (C)2014, Zhou Zhaoxiong

*

* 文件名称: TestStruct.c

* 文件标识:

* 内容摘要:用于演示结构体变量的用法

* 其它说明:

* 当前版本: V1.0

*     者:周兆熊

* 完成日期: 20140617

*

* 修改记录1// 修改历史记录, 包括修改日期、版本号、修改人及修改内容

* 修改日期: 20140617

* 号: V1.0

* 人: Zhou Zhaoxiong

* 修改内容:创建

**********************************************************************/

#include <stdio.h>

#include <string.h>

 

 

// 数据类型

typedef signed   char INT8;

typedef unsigned char UINT16;

typedef unsigned int  UINT32;

typedef signed   int  INT32;

 

 

// 员工信息结构体

typedef struct

{

       INT8    szEmployeeName[100];  // 员工姓名

       UINT16  iEmployeeAge;         // 员工年龄

       UINT32  iEmployeeNo;          // 员工工号

} TEmployeeInfo;

 

 

// 函数声明

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo); // 获取员工信息函数

INT32 main(void);

 

 

/****************************************************************

* 功能描述主函数                                            

* 输入参数                                                 

* 输出参数                                                

* 返回值: 0-执行成功  -1-执行失败                           

* 其他说明:  无                                                

* 修改日期        版本号        修改人        修改内容

* ----------------------------------------------------------------------------------------

* 20140617        V1.0      Zhou Zhaoxiong     创建

****************************************************************/

INT32 main(void)

{

    INT32          iRetValue      = 0;       // 该变量用于表示调用GetEmployeeInfo函数返回的值

    TEmployeeInfo *ptEmployeeInfo = NULL;    // 该变量用于存放员工信息

   

    // 调用函数对员工信息字段赋值, 并打印出来

    iRetValue = GetEmployeeInfo(ptEmployeeInfo);

    if (iRetValue != 0)

    {

        printf("exec GetEmployeeInfo failed.\n");

        return -1;

    }

       

    printf("员工信息为: \n姓名: %s\n年龄: %d\n工号: %d\n", ptEmployeeInfo->szEmployeeName, ptEmployeeInfo->iEmployeeAge, ptEmployeeInfo->iEmployeeNo);

 

    return 0;

}

 

 

/**********************************************************************

* 功能描述:对员工信息字段赋值

* 输入参数: ptEmployeeInfo: 员工信息结构体

* 输出参数: ptEmployeeInfo: 员工信息结构体

* 返回值: 0-成功  -1-失败

* 其它说明:无

* 修改日期          版本号           修改人         修改内容

* --------------------------------------------------------------------------------------

* 20140617           V1.0         Zhou Zhaoxiong      创建

***********************************************************************/

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo)

{

    // 先对输入的指针参数进行异常判断

    if (ptEmployeeInfo == NULL)

    {

        printf("Input parameter is NULL.\n");

        return -1;

    }

 

    strncpy((char *)ptEmployeeInfo->szEmployeeName, "Li Yuanfang", strlen("Li Yuanfang"));   // 对姓名字段赋值

    ptEmployeeInfo->iEmployeeAge = 100;       // 对年龄字段赋值

    ptEmployeeInfo->iEmployeeNo  = 123456;    // 对工号字段赋值

 

    return 0;     // 赋值成功, 返回0

}

 

         程序的运行结果如图1所示:

图1 采用指针传递时的程序代码运行结果

 

        从图1可以看出,函数GetEmployeeInfo的入参为空,不能实现赋值的功能。

 

三、改进后的采用指针传递时的程序代码

        既然程序打印出指针为空的信息,那么我们先对传入的指针进行赋值操作是不是就可以了呢?

        改进后的采用指针传递时的程序代码如下:

/**********************************************************************

* 版权所有 (C)2014, Zhou Zhaoxiong

*

* 文件名称: TestStruct.c

* 文件标识:

* 内容摘要:用于演示结构体变量的用法

* 其它说明:

* 当前版本: V1.0

*     者:周兆熊

* 完成日期: 20140617

*

* 修改记录1// 修改历史记录, 包括修改日期、版本号、修改人及修改内容

* 修改日期: 20140617

* 号: V1.0

* 人: Zhou Zhaoxiong

* 修改内容:创建

**********************************************************************/

#include <stdio.h>

#include <string.h>

 

 

// 数据类型

typedef signed   char INT8;

typedef unsigned char UINT16;

typedef unsigned int  UINT32;

typedef signed   int  INT32;

 

 

// 员工信息结构体

typedef struct

{

       INT8    szEmployeeName[100];  // 员工姓名

       UINT16  iEmployeeAge;         // 员工年龄

       UINT32  iEmployeeNo;          // 员工工号

} TEmployeeInfo;

 

 

// 函数声明

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo); // 获取员工信息函数

INT32 main(void);

 

 

/****************************************************************

* 功能描述主函数                                            

* 输入参数                                                

* 输出参数                                                

* 值: 0-执行成功  -1-执行失败                           

* 其他说明                                                 

* 改日期        版本号        修改人        修改内容

* --------------------------------------------------------------------------------------------

* 20140617        V1.0      Zhou Zhaoxiong     创建

****************************************************************/

INT32 main(void)

{

    INT32          iRetValue      = 0;       // 该变量用于表示调用GetEmployeeInfo函数返回的值

    TEmployeeInfo *ptEmployeeInfo = NULL;    // 该变量用于存放员工信息

 

    // 先对员工信息字段赋值, 防止空指针的存在

    strncpy((char *)ptEmployeeInfo->szEmployeeName, "Di Renjie", strlen("Di Renjie"));   // 对姓名字段赋值

    ptEmployeeInfo->iEmployeeAge = 150;       // 对年龄字段赋值

    ptEmployeeInfo->iEmployeeNo  = 654321;    // 对工号字段赋值

   

    // 调用函数对员工信息字段赋值, 并打印出来

    iRetValue = GetEmployeeInfo(ptEmployeeInfo);

    if (iRetValue != 0)

    {

        printf("exec GetEmployeeInfo failed.\n");

        return -1;

    }

       

    printf("员工信息为: \n姓名: %s\n年龄: %d\n工号: %d\n", ptEmployeeInfo->szEmployeeName, ptEmployeeInfo->iEmployeeAge, ptEmployeeInfo->iEmployeeNo);

 

    return 0;

}

 

 

/**********************************************************************

* 功能描述:对员工信息字段赋值

* 输入参数: ptEmployeeInfo: 员工信息结构体

* 输出参数: ptEmployeeInfo: 员工信息结构体

* 值: 0-成功  -1-失败

* 其它说明:

* 修改日期          版本号           修改人         修改内容

* -----------------------------------------------------------------------------------

* 20140617           V1.0         Zhou Zhaoxiong      创建

***********************************************************************/

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo)

{

    // 先对输入的指针参数进行异常判断

    if (ptEmployeeInfo == NULL)

    {

        printf("Input parameter is NULL.\n");

        return -1;

    }

 

    strncpy((char *)ptEmployeeInfo->szEmployeeName, "Li Yuanfang", strlen("Li Yuanfang"));   // 对姓名字段赋值

    ptEmployeeInfo->iEmployeeAge = 100;       // 对年龄字段赋值

    ptEmployeeInfo->iEmployeeNo  = 123456;    // 对工号字段赋值

 

    return 0;     // 赋值成功, 返回0

}

 

          程序的运行结果如图2所示:

图2 改进后的采用指针传递时的程序代码运行结果

 

       可见,程序出现了内存问题。原因是在传递之前,ptEmployeeInfo指针已经指向了确定的地址,不能让同一个指针同时指向不同的地址。

 

四、第二次改进后的程序代码

        既然不能用指针作为参数进行传递,那么我们就要考虑另外的方法。

        以下代码采用非指针的传递方式:

/**********************************************************************

* 版权所有 (C)2014, Zhou Zhaoxiong

*

* 文件名称: TestStruct.c

* 文件标识:

* 内容摘要:用于演示结构体变量的用法

* 其它说明:

* 当前版本: V1.0

*     者:周兆熊

* 完成日期: 20140617

*

* 修改记录1// 修改历史记录, 包括修改日期、版本号、修改人及修改内容

* 修改日期: 20140617

* 号: V1.0

* 人: Zhou Zhaoxiong

* 修改内容:创建

**********************************************************************/

#include <stdio.h>

#include <string.h>

 

 

// 数据类型

typedef signed   char INT8;

typedef unsigned char UINT16;

typedef unsigned int  UINT32;

typedef signed   int  INT32;

 

 

// 员工信息结构体

typedef struct

{

       INT8    szEmployeeName[100];  // 员工姓名

       UINT16  iEmployeeAge;         // 员工年龄

       UINT32  iEmployeeNo;          // 员工工号

} TEmployeeInfo;

 

 

// 函数声明

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo); // 获取员工信息函数

INT32 main(void);

 

 

/****************************************************************

* 功能描述主函数                                            

* 输入参数                                                 

* 输出参数                                                

* 值: 0-执行成功  -1-执行失败                           

* 其他说明                                                

* 修改日期        版本号        修改人        修改内容

* --------------------------------------------------------------

* 20140617        V1.0      Zhou Zhaoxiong     创建

****************************************************************/

INT32 main(void)

{

    INT32         iRetValue     = 0;      // 该变量用于表示调用GetEmployeeInfo函数返回的值

    TEmployeeInfo tEmployeeInfo = {0};    // 该变量用于存放员工信息

   

    // 调用函数对员工信息字段赋值, 并打印出来

    iRetValue = GetEmployeeInfo(&tEmployeeInfo);

    if (iRetValue != 0)

    {

        printf("exec GetEmployeeInfo failed.\n");

        return -1;

    }

       

    printf("员工信息为: \n姓名: %s\n年龄: %d\n工号: %d\n", tEmployeeInfo.szEmployeeName, tEmployeeInfo.iEmployeeAge, tEmployeeInfo.iEmployeeNo);

 

    return 0;

}

 

 

/**********************************************************************

* 功能描述:对员工信息字段赋值

* 输入参数: ptEmployeeInfo: 员工信息结构体

* 输出参数: ptEmployeeInfo: 员工信息结构体

* 值: 0-成功  -1-失败

* 其它说明:

* 修改日期          版本号           修改人         修改内容

* --------------------------------------------------------------

* 20140617           V1.0         Zhou Zhaoxiong      创建

***********************************************************************/

INT32 GetEmployeeInfo(TEmployeeInfo *ptEmployeeInfo)

{

    // 先对输入的指针参数进行异常判断

    if (ptEmployeeInfo == NULL)

    {

        printf("Input parameter is NULL.\n");

        return -1;

    }

 

    strncpy((char *)ptEmployeeInfo->szEmployeeName, "Li Yuanfang", strlen("Li Yuanfang"));   // 对姓名字段赋值

    ptEmployeeInfo->iEmployeeAge = 100;       // 对年龄字段赋值

    ptEmployeeInfo->iEmployeeNo  = 123456;    // 对工号字段赋值

 

    return 0;     // 赋值成功, 返回0

}

 

        程序的执行结果如图3所示:

图3第二次改进后的程序代码执行结果

 

        从图3可以看出,程序执行结果正确,得到了我们想要的结果。

 

五、总结

        在编写代码的过程中,我们需要注意以下方面:

       (1) 程序头部、函数头部及重要的程序语句处一定要有注释,这体现了软件开发人员的专业素养。

       (2) 函数中出现的变量在定义的同时要进行初始化,函数在调用之前一定要先进行声明。

       (3) 对于函数中的指针变量参数,在使用之前一定要先进行异常判断(即判断其是否为NULL)。

       (4) 对于有返回值的函数,要用不同的返回值来区别不同的执行结果,并在重要的地方打印出提示信息,方便对代码的调试。

 

        指针是C语言的精华所在,同时也是难点所在。对于一个合格的软件开发工程师来说,一定要熟练掌握指针的使用方法。

 

 

 

(本人微博:http://weibo.com/zhouzxi?topnav=1&wvr=5,微信号:245924426,欢迎关注!)

目录
相关文章
|
27天前
|
存储 编译器 C语言
【C语言】C语言的变量和声明系统性讲解
在C语言中,声明和定义是两个关键概念,分别用于告知编译器变量或函数的存在(声明)和实际创建及分配内存(定义)。声明可以多次出现,而定义只能有一次。声明通常位于头文件中,定义则在源文件中。通过合理组织头文件和源文件,可以提高代码的模块化和可维护性。示例包括全局变量、局部变量、函数、结构体、联合体、数组、字符串、枚举和指针的声明与定义。
48 12
|
1月前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
142 14
|
1月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
173 10
|
1月前
|
C语言
【C语言】全局搜索变量却找不到定义?原来是因为宏!
使用条件编译和 `extern` 来管理全局变量的定义和声明是一种有效的技术,但应谨慎使用。在可能的情况下,应该优先考虑使用局部变量、函数参数和返回值、静态变量或者更高级的封装技术(如结构体和类)来减少全局变量的使用。
38 5
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
169 13
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
2月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
76 11
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
62 4
|
3月前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
97 10
|
3月前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。