`
mmdev
  • 浏览: 12845093 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

[C] struct的初始化,拷贝及指针成员的使用技巧

 
阅读更多
struct是C中重要的ADT。但是在一般讲C的书中,往往只介绍了struct的定义、顺序初始化及位域。

本文将笔者曾经用到的、看到的知识点罗列出来,与大家分享。

为了方便后面的介绍,先定义一个struct类型:
struct User
{
int id; //id
char name[100]; //user name
char *home; //home directory
int passwd; //password
};


1 初始化
struct数据有3中初始化方法:顺序,C风格及C++风格的乱序。

1)顺序
这种方法很常见,在一般的介绍C的书中都有介绍。顺序初始化的特点是: 按照成员定义的顺序,从前到后逐个初始化;允许只初始化部分成员;在被初始化的成员之前,不能有未初始化的成员;未显示初始化的自动设为0。
eg:
struct User oneUser = {10, "Lucy", "/home/Lucy"};
初始化之后,oneUser各个成员的值为:
oneUser.id = 10;
oneUser.name = "Lucy";
oneUser.home = "/home/Lucy";
oneUser.passwd = 0;

2)乱序(C风格)
顺序的缺陷是必须按成员定义的顺序逐个初始化,不能间隔。而乱序的方式则很好的解决了这个问题,因为这种方式是按照成员名进行。
eg:
struct User oneUser = {
.name = "Lucy",
.id = 10,
.home = "/home/Lucy"
};

3)乱序(C++风格)
C++风格的乱序初始化方式跟C风格的一样,只是它更常用在C++代码里。
eg:
struct User oneUser = {
name:"Lucy",
id:10,
home:"/home/Lucy"
};


不论是哪种方式,都允许只初始化部分成员;未被初始化的成员默认为0(指针类型的成员默认为NULL)。两种乱序初始化方法,既可以用在C代码中,也可以用在C++代码中。


2 拷贝
struct有两种拷贝方式,一是直接赋值(=),另一种是用memcpy等库函数实行内存拷贝。
eg:
struct Temp a, b;
//Set value to members of b
a = b;
memcpy(&a, &b, sizeof(a));
不管是哪种拷贝方式,都是将以&b开始的,大小为sizeof(struct Temp)的内存区域中的数据,简单地复制到以&a开始的,同样大小的内存区域。所以,这两种方式与按成员赋值是等价的:
a.id = b.id;
a.name = b.name;
a.home = b.home;
a.passwd = b.passwd;
由此,我们不难看出,上面两种拷贝方式都属于浅拷贝。


3 指针成员的两种使用技巧
1) 为多个指针成员同时分配内存
如果一个struct中有多个指针类型的成员,我们通常需要为每个指针逐个成员分配内存空间,并在使用完时释放它们;这样频繁调用malloc/free,难免让人生厌。如果在分配内存之前,每个指针所指向内存区域的大小是确定的,那么,我们可以为所有指针一次性分配内存区域;并在使用完后,一次性释放。
eg:
struct Inode
{
int id;

char *file;
int fie_len;

char *path;
int path_len;

char *user;
int user_len;
};

struct Inode data = {
.file_len = X,
.path_len = Y,
.user_len = X
};

//Allocate memory
data.file = (char *)malloc(data.file_len + data.path_len + data.user_len);
data.path = data.file + data.file_len;
data.user = data.path + data.path_len;


//User
...


//Free memory
free(data.file);


2)变长数组的另类实现
将下面的定义
struct File
{
TypeA dataA;
......
char *data;
TypeN dataN;
};
改成:
struct File
{
TypeA dataA;
......
TypeN dataN;
char data[0];
};
即将指针成员换成大小为0的一维数组, 作为struct的最后一个成员(数据结构的可变部分必须作为最后一个成员),有两个优点:
(1) 在紧邻struct处为data分配内存区域,这样在分配内存后无须为data赋值;
(2) 利用数组的特性,以指针的方式通过越界访问data数组外的内存区域。
eg:
struct File *pVar = (struct File *)malloc(sizeof(struct File) + DATA_LEN);
strncpy(pVar->data, "Source data", DATA_LEN);

ref:http://blog.chinaunix.net/space.php?uid=8735300&do=blog&id=2016862

分享到:
评论

相关推荐

    C语言讲义.doc

    4.1.1 定义结构体struct和初始化 71 4.1.2 访问结构体成员 71 4.1.3 结构体的内存对齐模式 72 4.1.4 指定结构体元素的位字段 72 4.1.5 结构数组 72 4.1.6 嵌套结构 73 4.1.7 结构体的赋值 73 4.1.8 指向结构体的指针...

    C++智能指针-unique-ptr智能指针详解.pdf

    和可以⽤ make_shared() 模板函数初始化 shared_ptr 指针不同,C++11 标准中并没有为 unique_ptr 类型指针添 加类似的模板函数。 3) 基于 unique_ptr 类型指针不共享各⾃拥有的堆内存,因此 C++11 标准中的 unique_...

    智能指针shared-ptr的用法.pdf

    不要⽤⼀个原始指针初始化多个shared_ptr,原因在于,会造成⼆次销毁,如下所⽰: int *p5 = new int; std::shared_ptr<int> p6(p5); std::shared_ptr<int> p7(p5);// logic error 不要在函数实参中创建shared_ptr...

    C++11unique-ptr智能指针详解.pdf

    和可以⽤ make_shared() 模板函数初始化 shared_ptr 指针不同,C++11 标准中并没有为 unique_ptr 类型指针添加类似的模 板函数。 3) 基于 unique_ptr 类型指针不共享各⾃拥有的堆内存,因此 C++11 标准中的 unique_...

    C++11unique-ptr智能指针详解(1).pdf

    和可以⽤ make_shared() 模板函数初始化 shared_ptr 指针不同,C++11 标准中并没有为 unique_ptr 类型指针添加类似的模 板函数。 3) 基于 unique_ptr 类型指针不共享各⾃拥有的堆内存,因此 C++11 标准中的 unique_...

    C++中各种初始化方式示例详解

    本文主要给大家介绍了关于C++初始化方式的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。 C++小实验测试:下面程序中main函数里a.a和b.b的输出值是多少? #include struct foo { ...

    传智播客扫地僧视频讲义源码

    本教程共分为5个部分,第一部分是C语言提高部分,第二部分为C++基础部分,第三部分为C++进阶部分,第四部分为C、C++及数据结构基础部分,第五部分为C_C++与设计模式基础,内容非常详细. 第一部分 C语言提高部分目录...

    新手学习C++入门资料

    这些关键字能作为函数和变量的标识符在C程序中使用,尽管C++包含了所有的C,但显然没有任何C++编译器能编译这样的C程序。 C程序员可以省略函数原型,而C++不可以,一个不带参数的C函数原型必须把void写出来。而C++...

    深度探索模C++对象模型PDF

    2.4 成员们的初始化队伍(Member Initialization List) 第3章 Data语意学(The Semantics of Data) 3.1 Data Member的绑定(The Binding of a Data Member) 3.2 Data Member的布局(Data Member Layout) 3.3 ...

    深度探索C++对象模型 超清版

    2.4 成员们的初始化队伍(Member Initialization List) 第3章 Data语意学(The Semantics of Data) 3.1 Data Member的绑定(The Binding of a Data Member) 3.2 Data Member的布局(Data Member Layout) 3.3 ...

    摩托罗拉C++面试题

    而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值. (2) 不存在NULL引用,引用必须与合法的存储单元关联;而指针则可以是NULL. (3) 引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象...

    《深度探索C++对象模型》(Stanley B·Lippman[美] 著,侯捷 译)

    2.4 成员们的初始化队伍(Member Initialization List) 第3章 Data语意学(The Semantics of Data) 3.1 Data Member的绑定(The Binding of a Data Member) 3.2 Data Member的布局(Data Member Layout) 3.3 ...

    gsoap 2.8 (SOAP/XML 关于C/C++ 语言的自动化实现工具内附 CSharp webservice例子,及GSOAP client和server例子)

     struct soap *soap_new() 定义并初始化环境变量并返回一个该变量的指针  struct soap *soap_copy(struct soap *soap) 定义一个环境变量并从已有的环境变量中拷贝环境信息  环境变量定义好后就可以重复使用而不必...

    c/c++ 学习总结 初学者必备

    (C语言里参数传递都是传值,是一个拷贝,修改指针,只是改变了拷贝的指向,原指针指向并没有改变,而修改指针的内容则是可以的。)如果函数的参数是一个指针,不要指望用该指针去申请动态内存。(即上面所说的修改...

    c++ 面试题 总结

    系统会初始化static int变量为0,但该值会一直保存,所谓的不可重入... -------------------------------------------------------------------------- 13.写出运行结果: {// test1 char str[] = "world"; cout (str...

    多线程与智能指针.pdf

    //初始化 attr中为操作系统实现⽀持的线程所有属性的默认值 pthread_attr_init(&attr); pthread_attr_destroy(&attr); 分离线程 线程创建默认是⾮分离的,当pthread_join()函数返回时,创建的线程终⽌,释放⾃⼰占...

    ARM_Linux启动分析.pdf

    这一部分的启动过程在2.4.x内核中简化了不少,缺省的独立初始化过程只剩下网络 (sock_init())和创建事件管理核心线程,而其他所需要的初始化都使用__initcall()宏 包含在do_initcalls()函数中启动执行。...

    程序设计教程 陈家骏等编著

    6.4.2 成员对象的初始化 222 6.4.3 拷贝构造函数 223 6.5 const 成员函数 226 6.6 静态成员 228 6.7 友元 231 6.8 小结 234 6.9 习题 235 第7章 操作符重载 238 7.1 操作符重载的需要性和基本原则 238 7.2 作为成员...

    LuaBind 源码 (Lua增强库)

    的函数并初始化 LuaBind需要使用的 状态机全局结构. 如果你不调用这个函数, 你会在后面 触发一个 断言 . 不没有一个对应的关闭函数.因为,一旦一个类被注册到Lua,真没有什么好 的方法去移除它.部分原因是任何剩余的类...

    传智播客_C++基础课程讲义_v1.0.7

    面试题6:虚函数表指针(VPTR)被编译器初始化的过程,你是如何理解的? 6 面试题7:父类的构造函数中调用虚函数,能发生多态吗? c++编译器多态实现原理 6 面试题8:为什么要定义虚析构函数? 6 其他 6 4.3多态...

Global site tag (gtag.js) - Google Analytics