总结几种结构体初始化的方法(转)

总结几种结构体初始化的方法


转自:http://www.cnblogs.com/vongang/archive/2011/07/30/2122076.html


结构体能自由组装数据,是一种很常见的数据打包方法。当我们定义一个结构体后,没有初始化就使用,就会使用到垃圾数据,而且这种错误很难发现。对于定义的任何变量,我们最好都先初始化。

 

除了使用memsetZeroMemory之外,有没有更简单的方法初始化呢?因为有时候每定义一个结构体,就使用一次memset,也会觉得很繁琐。

 

我这里总结三种方法,如果大家有什么好的方法,不妨加上去。

 

1、结构体的构造函数中初始化。

 

2、继承模板类初始化

 

3、定义时初始化

在C++中,结构体与类在使用上已没有本质上的区别了,所以可以使用构造函数来初始化。如下代码所示:

  struct Stu
 {
  int  nNum;
  bool bSex;
  char szName[20];
  char szEmail[100];

  //构造函数初始化
  Stu()
  {
   nNum = 0;
   bSex = false;
   memset(szName,0,sizeof(szName));
   memset(szEmail,0,sizeof(szEmail));

  }
 };

你可能已经发现了,如果结构体中有大量成员,一个个赋值,相当麻烦。那么你可以这样写:

 struct Stu
 {
  int  nNum;
  bool bSex;
  char szName[20];
  char szEmail[100];

  //构造函数初始化
  Stu()
  {
    memset(this,0,sizeof(Stu));
    //或者是下面的格式
    //memset(&nNum,0,sizeof(Stu));

  }
 };

如果在结构体中分配了指针,并且指针指向一个堆内存,那么就在析构函数中释放。以上便是在构造函数中初始化。

2、继承模板类初始化

首先定义一个模板基类:
template <typename T>
class ZeroStruct
{
public:
    ZeroStruct()
    {
        memset(this,0,sizeof(T));
    }
};

之后定义的结构体都继承于此模板类。 

    struct Stu:ZeroStruct<Stu>
    {
        int        nNum;
        bool    bSex;
        char    szName[20];
        char    szEmail[100];
    };

这样也能实现初始化。

3、定义时初始化。

    struct Stu
    {
        int        nNum;
        bool    bSex;
        char    szName[20];
        char    szEmail[100];
    }; 

//定义时初始化
Stu stu1 = {0};

在有的结构体中,第一个成员表示结构体的大小,那么就可以这样初始化:

 struct Stu
 {
int nSize; //结构体大小
  int  nNum;
  bool bSex;
  char szName[20];
  char szEmail[100];
 };


 Stu stu1 = {sizeof(Stu),0};

后面的0,可以省略掉,直接写成:Stu stu1 = {sizeof(Stu)};后面自动会用0填充。

总结分析:

以上三种,是据我所知的初始化结构体方法。

前面两种,实际上已经把结构体给类化了,和类的使用差不多。第三种,是纯粹的结构体的写法。

如果用途仅仅限定为结构体,我建议不要加上构造函数,也不要继承于那个模板类,因为这个时候结构体实际上已经是类了。在定义结构体时,将无法使用第三种方式去初始化,当然,此时也不需要初始化了。

看看微软定义的结构体,基本上都没有构造函数和析构函数。因为结构体的意义很明确,它仅仅是对数据的一个包装,如果加上了方法,其意义就变了。



参考文章:

http://blog.youkuaiyun.com/adaptiver/article/details/7494081
http://blog.hjenglish.com/bedford/

在阅读GNU/Linux内核代码时,我们会遇到一种特殊的结构初始化方式。该方式是某些C教材(如谭二版、K&R二版)中没有介绍过的。这种方式称为指定初始化(designated initializer)。下面我们看一个例子,Linux-2.6.x/drivers/usb/storage/usb.c中有这样一个结构体初始化项目:
static struct usb_driver usb_storage_driver = {
       .owner = THIS_MODULE,
       .name = "usb-storage",
       .probe = storage_probe,
       .disconnect = storage_disconnect,
       .id_table = storage_usb_ids,
};
    乍一看,这与我们之前学过的结构体初始化差距甚远。其实这就是前面所说的指定初始化在Linux设备驱动程序中的一个应用,它源自ISO C99标准。以下我摘录了C Primer Plus第五版中相关章节的内容,从而就可以很好的理解2.6版内核采用这种方式的优势就在于由此初始化不必严格按照定义时的顺序。这带来了极大的灵活性,其更大的益处还有待大家在开发中结合自身的应用慢慢体会。
    已知一个结构,定义如下
struct book {
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};
    C99支持结构的指定初始化项目,其语法与数组的指定初始化项目近似。只是,结构的指定初始化项目使用点运算符和成员名(而不是方括号和索引值)来标识具体的元素。例如,只初始化book结构的成员value,可以这样做:
    struct book surprise = { .value = 10.99 };
    可以按照任意的顺序使用指定初始化项目:
    struct book gift = { .value = 25.99,
                                    .author = "James Broadfool",
                                    .title = "Rue for the Toad"};
    正像数组一样,跟在一个指定初始化项目之后的常规初始化项目为跟在指定成员后的成员提供了初始值。另外,对特定成员的最后一次赋值是它实际获得的值。例如,考虑下列声明:
    struct book gift = { .value = 18.90,
                                    .author = "Philionna pestle",
                                    0.25};
    这将把值0.25赋给成员value,因为它在结构声明中紧跟在author成员之后。新的值0.25代替了早先的赋值18.90。
    有关designated initializer的进一步信息可以参考c99标准的6.7.8节Ininialization。

摘自: http://blog.youkuaiyun.com/zhsxcn/archive/2008/02/27/2125211.aspx

5.22 特定的初始化

标准C89需要初始化语句的元素以固定的顺序出现,和被初始化的数组或结构体中的元素顺序一样。

在ISO C99中,你可以按任何顺序给出这些元素,指明它们对应的数组的下标或结构体的成员名,并且GNU C也把这作为C89模式下的一个扩展。这个扩展没有在GNU C++中实现。

为了指定一个数组下标,在元素值的前面写上“[index] =”。比如:

      

int a[6] = { [4] = 29, [2] = 15 };
            

相当于:

      

int a[6] = { 0, 0, 15, 0, 29, 0 };
            

下标值必须是常量表达式,即使被初始化的数组是自动的。

一个可替代这的语法是在元素值前面写上“.[index]”,没有“=”,但从GCC 2.5开始就不再被使用,但GCC仍然接受。为了把一系列的元素初始化为相同的值,写为“[first ... last] = value”。这是一个GNU扩展。比如:

      

int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
            

如果其中的值有副作用,这个副作用将只发生一次,而不是范围内的每次初始化一次。

注意,数组的长度是指定的最大值加一。

在结构体的初始化语句中,在元素值的前面用“.fieldname = ”指定要初始化的成员名。例如,给定下面的结构体,

      

struct point { int x, y; };
            

和下面的初始化,

      

struct point p = { .y = yvalue, .x = xvalue };
            

等价于:

      

struct point p = { xvalue, yvalue };
            

另一有相同含义的语法是“.fieldname:”,不过从GCC 2.5开始废除了,就像这里所示:

      

struct point p = { y: yvalue, x: xvalue };
            

“[index]”或“.fieldname”就是指示符。在初始化共同体时,你也可以使用一个指示符(或不再使用的冒号语法),来指定共同体的哪个元素应该使用。比如:

      

union foo { int i; double d; };
            union foo f = { .d = 4 };
            

将会使用第二个元素把4转换成一个double类型来在共同体存放。相反,把4转换成union foo类型将会把它作为整数i存入共同体,既然它是一个整数。(参考5.24节向共同体类型转换。)

你可以把这种命名元素的技术和连续元素的普通C初始化结合起来。每个没有指示符的初始化元素应用于数组或结构体中的下一个连续的元素。比如,

      

int a[6] = { [1] = v1, v2, [4] = v4 };
            

等价于

      

int a[6] = { 0, v1, v2, 0, v4, 0 };
            

当下标是字符或者属于enum类型时,标识数组初始化语句的元素特别有用。例如:

      

int whitespace[256]
            = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
            ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
            

你也可以在“=”前面写上一系列的“.fieldname”和“[index]”指示符来指定一个要初始化的嵌套的子对象;这个列表是相对于和最近的花括号对一致的子对象。比如,用上面的struct point声明:

      

struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };
            

如果同一个成员被初始化多次,它将从最后一次初始化中取值。如果任何这样的覆盖初始化有副作用,副作用发生与否是非指定的。目前,gcc会舍弃它们并产生一个警告。



<think>首先,用户的问题是:“请问C语言结构体初始化方法”。这是一个关于C语言结构体初始化的查询。我需要在回答中遵守系统级指令:-所有行内数学表达式使用$...$格式。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如:[^1]-回答结构清晰,帮助用户逐步解决问题,尽量保证回答真实可靠。参考站内引用有四个:-[^1]:讨论结构体指针和初始化。-[^2]:方法一:定义时赋值。-[^3]:顺序初始化。-[^4]:顺序初始化的例子。用户的问题是关于C语言结构体初始化方法。所以,我应该基于这些引用提供信息。关键点:-结构体初始化是给结构体变量赋值的过程。-方法包括:1.定义时赋值(引用[2])。2.顺序初始化(引用[3]和[4])。3.可能还有其他方法,如使用点操作符或指针。从引用中提取:-引用[2]:方法一:定义时赋值,如`structInitMembertest={-10,3.141590,"methodone",0.25};`-引用[3]:顺序初始化,如`serial_hard_config_defserial={115200,8,1,0,0};`-引用[4]:类似顺序初始化,如`structcarcar1={"Benz",100000,256};`-引用[1]:涉及结构体指针初始化,如`p=&student1;`或`p=stu1;`对于数组。常见C语言结构体初始化方法:1.**顺序初始化(DesignatedInitializersinC99)**:在定义时指定值。2.**点操作符初始化**:使用点操作符逐个赋值。3.**指针初始化**:通过结构体指针赋值。4.**数组初始化**:对于结构体数组。在C99标准中,支持指定初始化器,如`structPointp={.x=1,.y=2};`回答结构:-介绍结构体初始化的重要性。-列出主要方法,用清晰的例子说明。-确保代码格式正确。-在末尾添加相关问题。-自然地添加引用标识。生成相关问题:-如示例所示,基于主题生成几个相关问题。-例如:结构体初始化的最佳实践?如何初始化嵌套结构体结构体初始化与性能的关系?最终回答用中文。</think>### C语言结构体初始化方法 在C语言中,结构体(struct)是一种用户自定义的数据类型,用于组合不同类型的数据成员。初始化结构体是为其成员变量赋初始值的过程,这有助于避免未定义行为并提高代码可读性。以下是常见的结构体初始化方法,基于C语言标准(如C89/C99),我将逐步解释并给出示例。所有代码示例均使用C语言语法。 #### 1. **顺序初始化(定义时赋值)** 这是最基础的方法,在定义结构体变量时,按成员声明顺序直接赋值。适用于所有C版本,但需确保值顺序与成员顺序严格匹配。 - **示例代码**: ```c // 定义结构体 struct Student { char name[20]; int age; float score; }; // 初始化结构体变量 struct Student student1 = {"Alice", 20, 95.5}; // 顺序赋值: name, age, score ``` - **优点**:简洁高效。 - **缺点**:如果成员顺序变化,初始化代码需手动调整,易出错[^2][^4]。 #### 2. **指定成员初始化(C99标准引入)** 在C99及以上版本,支持使用点操作符(`.`)指定成员初始化。这允许跳过某些成员或乱序赋值,未指定的成员自动初始化为0或NULL。 - **示例代码**: ```c struct Point { int x; int y; int z; }; // 指定成员初始化 struct Point p1 = { .y = 30, .x = 10 }; // z未指定,默认为0 ``` - **优点**:灵活,可读性强,避免顺序依赖问题。 - **缺点**:仅支持C99及以上编译器[^2][^3]。 #### 3. **点操作符逐个赋值** 在定义结构体变量后,通过点操作符单独为每个成员赋值。适用于需要动态初始化或条件赋值场景。 - **示例代码**: ```c struct Car { char brand[20]; double price; int maxSpeed; }; struct Car car1; // 先定义变量 // 逐个成员赋值 strcpy(car1.brand, "Toyota"); car1.price = 150000.0; car1.maxSpeed = 200; ``` - **优点**:控制精细,适合复杂逻辑。 - **缺点**:代码冗长,可能增加错误风险[^4]。 #### 4. **结构体指针初始化** 通过结构体指针进行初始化,常用于动态内存分配或函数参数传递。需先获取结构体地址。 - **示例代码**: ```c struct Student student1 = {"Bob", 22, 88.0}; struct Student *p = &student1; // 指针指向结构体变量 // 通过指针赋值 p->age = 23; // 修改成员值 ``` - **数组指针初始化示例**: ```c struct Student stuArray[3] = {{"Tom", 21, 90.0}, {"Jerry", 19, 85.0}}; struct Student *pArray = stuArray; // 指向数组首地址,无需& pArray[0].score = 92.0; // 访问数组元素 ``` - **优点**:高效处理动态数据。 - **缺点**:需管理指针安全,避免空指针或越界[^1]。 #### 5. **嵌套结构体初始化** 当结构体包含其他结构体成员时,可以使用复合初始化。 - **示例代码**: ```c struct Address { char city[20]; int zipCode; }; struct Person { char name[20]; struct Address addr; }; // 嵌套初始化(顺序或指定成员) struct Person person1 = {"Charlie", {"Beijing", 100000}}; // 顺序方式 struct Person person2 = { .name = "David", .addr = { .city = "Shanghai", .zipCode = 200000 } }; // C99指定方式 ``` - **优点**:支持复杂数据结构。 - **缺点**:语法稍复杂,需注意成员层级。 #### 性能与最佳实践 - **性能考虑**:顺序初始化和指定成员初始化在编译时完成,效率高;点操作符赋值可能增加运行时开销。指针初始化在内存操作上高效,但需注意分配/释放[^1][^3]。 - **推荐方法**:优先使用C99的指定成员初始化(如 `.member = value`),以提高可读性和可维护性。在旧版C中,使用顺序初始化。 - **常见错误**:成员类型不匹配、顺序错误或未初始化所有成员,可能导致未定义行为。始终初始化所有成员以避免安全隐患。 如需进一步学习,可参考C语言标准文档或相关教程[^1][^2][^3][^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值