C语言(Head First C)-6_1:结构、联合与位字段:创建自己的结构

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!

 6_1:结构、联合与位字段:创建自己的结构

 

 目前为止,我们接触了C语言的基本数据类型;但如果想表示数字,文本以外的其他东西,或为现实世界中的事物建立模型,就显得力不从心了;

 结构将帮助创建自己的结构,模拟错综复杂的事物;

 我们将学习:

     如何把基本数据类型组成结构 以及 用联合处理生活的不确定性;如果想简单的模拟Y/N,可以用位字段;

 

 有时要传很多数据:

     C可以处理很多不同类型数据:小数字、大数字、浮点数、字符与文本;但实际中,事物往往需要一条以上的数据来记录;

 (Code6_1)

6_1-methods.h

/*
 * 打印目录项
 */
void catalog(const char * name, const char * species, int teeth, int  age);

/*
 * 打印贴出的标签
 */
void label(const char * name, const char * species, int teeth, int age);

6_1-methods.c

#include <stdio.h>
#include "6_1-methods.h"

/*
 * 打印目录项
 */
void catalog(const char * name, const char * species, int teeth, int  age){
    printf("%s is a %s with %i teeth, he is %i\n",name,species,teeth,age);
    
}

/*
 * 打印贴出的标签
 */
void label(const char * name, const char * species, int teeth, int age){
    printf("Name:%s\nSpecies:%s\nTeeth:%i\nAge:%i\n",name,species,teeth,age);
    
}

6_1-moredata.c

#include <stdio.h>
#include "6_1-methods.h"

int main() {
    
    catalog("Flower", "hahah", 10, 26);
    label("Flower", "hahah", 10, 26);
    
    return 0;
    
}

 注:const char * 表示传递的字符串参数,需要是字符串字面值;

 我们描述了一个人的信息,分别在两个函数中进行了诸多参数的传递,不算太坏,但还是有点乱……如果多了一条描述信息需要打印呢...

 

 怎样才能只描述一样东西,而不传那么多参数呢?

     我们需要一样东西,能让你在一条大数据中记录多条数据;

 

 用结构创建结构化数据类型:

 如果需要把一批数据打包成一样东西,就可以使用结构(struct);

     struct是structured data type(结构化数据类型)的缩写;有了结构就可以像下面这样把不同类型的数据写在一起,封装成一个新的大数据类型;

 (Code6_2)

/*
 * struct
 */

#include <stdio.h>

struct person{
    const char * name;
    const char * species;
    int teeth;
    int age;
};

int main() {
    
    struct person flower = {"Flower","hahah",14,26};
    
    printf("%s\n",flower.name);
    
    return 0;
}

 上述代码创建了一个新的自定义数据结构,他由一批其他数据组成;虽然和数组有类似,但也明显不同:

 不同点:

     结构的大小固定;

     结构中的数据都有名字;

 

 创建数据:

     只需要保证每条数据按照它们在结构体中定义的顺序出现即可;(参看Code6_2)

 

 现在我们修改函数,只需要传递person结构就行了:void catalog(struct person r);

 调用也简单多了:catalog(flower);

 

 这样做的好处:

     修改结构的内容时,不必修改使用它的函数;调用的函数只关心它是一个person,而不关注其中是不是多了一个字段;因为person已经有了所有的字段;

     所以,使用结构,代码易读,也能更好的应对变化;

 

 使用点运算符读取结构字段:

     尽管结构可以像数组那样在结构中保存字段,但读取时只能按名访问(不能用下标的方式);

     可以使用“.”运算符访问结构字段;(参看Code6_2)

 

 小结:

 const char * 用来保存你不想修改的字符串,也就是字符串字面值;

 存储字符串的方式,可以用字符串指针,也可以用字符数组,像char name[20];

 不同于数组变量是一个指向数组的指针;结构变量只是结构本身的名字;

 

 聚焦存储器中的结构:

 

 复制的是指向字符串的指针,而非字符串本身:

     当把一个结构变量赋给另一个结构变量,计算机会复制结构的内容(重新分配存储空间,大小相同);如果结构中含有指针,那么复制的仅仅是指针的值;

     在定义结构时,你并没有让计算机在存储器中创建任何东西,只给了计算机一个模板,告诉他你希望新的数据类型长什么样子;

     当定义新变量的时候(struct person flower = {"Flower","hahah",14,26};),计算机则需要在存储器中为结构的实体创建空间,这块空间必须足够大,以装下结构中所有字段;

     切记,为结构变量赋值相当于叫计算机复制数据;

 (P6_1)

 

 结构字段在存储器中的顺序和变量本身的顺序是相同,但是并不全是紧挨着摆放的,可能会有一些小间隙;因为 计算机总是希望数据能对齐字边界(word boundary);如果计算机的字长是32位,就不希望某个变量(比如short)跨越32位的边界保存,而是从下一个32位字开始的地方保存short;这种是为了防止某个字段跨越过字边界;如果一个字中,能放下几个字段,计算机就会这样做,而不会一个字段使用一个字;

 是所以如此在意字边界,是因为:

     计算机按字从存储器中读取数据,如果某个字段跨越了多个字,CPU就必须读取多个存储单元;并以某种方式把读取到的值合并起来;会很慢;

 

 

 结构中的结构:

 定义结构其实就是在创建新的数据类型;把现有的类型组合,描述更复杂的东西;我们也可以使用结构创建结构;

 (Code6_3)

/*
 * structs
 */

#include <stdio.h>

struct preferences{
    const char * food;
    float exercise_hours;
};

struct person{
    const char * name;
    const char * species;
    int teeth;
    int age;
    struct preferences care;//这叫嵌套(nesting)
};

int main() {
    
    struct person flower = {"Flower","hahah",14,26,{"meat",7.5}};
    
    printf("%s\n",flower.care.food);
    
    return 0;
}

 可以使用和之前一样的数组语法创建变量;

 一旦把结构组合起来,就可以使用一连串的"."运算符来访问字段;

 

 为什么要嵌套定义结构:

 为了对抗复杂性,建立更强大的数据块,描述更复杂的东西,比如网络流和视频图像;

 

 当我们定义结构时,需要使用struct关键字,定义变量的时候,也要使用struct关键字(struct person flower = ...),有没有简单的方法?

 

 用typedef为结构体命名:

 C中可以为结构创建别名;只需要在struct关键字前加上typedef,并在右花括号后写上类型名,就可以在任何地方使用这种新类型;

 typedef struct structname {

 

 } typealias;

 使用typedef可以用来缩短代码长度,并让代码更容易阅读;

 

 结构有两个名字:一个是结构名(如structname),一个是类型名(typealias);其实一般只用一个就够了,如果只写类型名,编译器也没意见,这种叫做匿名结构;

 (Code6_4)

/*
 * typedef
 */

#include <stdio.h>

typedef struct{
    float tank_capacity;
    int tank_psi;
    const char * suit_material;
} equipment;

typedef struct scuba{
    const char * name;
    equipment kit;
} diver;

void badge(diver d ){
    printf("Name:%s\nTank:%2.2f(%i) Suit:%s\n",d.name,d.kit.tank_capacity,d.kit.tank_psi,d.kit.suit_material);
    
}

int main() {
    
    diver randy = {"Randy",{5.5,3500,"Neprence"}};
    badge(randy);
    
    return 0;
}

 log:

 Name:Randy

 Tank:5.50(3500) Suit:Neprence

 

 要点:

 -结构是一种由一系列其他数据类型组成的数据类型;

 -结构的大小固定;

 -结构字段按名访问,用<结构>.<字段名>语法(也叫点表示法);

 -结构字段在存储器中保存的顺序和他们出现在代码中的顺序相同;

 -可以嵌套定义结构;

 -typedef创建数据类型的别名;

 -用typedef定义结构时可以省略结构名;

 -C中的赋值都是复制数据的,若想实现复制数据的引用,就应该赋指针;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值