黑马程序员——c语言学习---数据结构

本文详细探讨了C语言中的数据结构,包括枚举、结构体、数组和共用体的应用。通过实例解析,阐述了如何有效地利用这些数据类型进行程序设计,帮助读者深化对C语言数据组织和管理的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-----------Java培训Android培训IOS培训.Net培训期待与您交流!------------ 
本节来讨论c语言主要的数据结构,包括数组、结构体、共用体、枚举。首先从数组开始。
1、数组
数组为同一类型的基本数据的集合。我们知道,基本数据类型都占据一定的内存空间,基本数据类型的定义,实际上就是内存地址的分配过程,同样的,数组作为基本数据类型的集合,在创建时也必须进行内存的分配。以下都为正确的数组创建方法:
        int num1[4]={0,1,2,3};
        int num2[4]={0,1};
        int num3[4]={[2]=2,[3]=3};
        int num4[]={0,1,2,3};
        int n=3;int num5[n];
        int num6[0]; 
错误的示例:
        int num5[]; // 未明确范围
        int num6={0,1,2,3}; // 格式不对
        int num7[];num7={0,1,2,3}; // 整体赋值必须在定义时赋值
        int n=3;int num8[n]={0,1,2,3}; // 错误
        int num9[-1]; // 没有负数个

特殊的数组:
a、字符数组(字符串)
在c语言中通过字符数组的方式表示字符串,字符串的结尾不是字符数组的结尾,而是字符数组中出现的第一个‘\0’。
    char str[]={'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0'};    
    printf("%s\n", str);
也可以采用下面的方式创建(这两者不等价):
    char *str="Hello World!";
    printf("%s\n", str);
b、多维数组
有的时候采用单一的数组也可能满足不了需求,这时候就需要用到多维数组,他的定义和普通的数组完全一样,只不过他的每一个元素本身都是一个数组。我们来看一下多维数组的存储方式:
    int a[2][2]={{1,2},{1,2}};
    
    printf("a[0][0]: %p \n", &a[0][0]);
    printf("a[0][1]: %p \n", &a[0][1]);
    printf("a[1][0]: %p \n", &a[1][0]);
    printf("a[1][1]: %p \n", &a[1][1]);
输出结果:
a[0][0]: 0x7fff5fbff8c0 
a[0][1]: 0x7fff5fbff8c4 
a[1][0]: 0x7fff5fbff8c8 
a[1][1]: 0x7fff5fbff8cc 
从上述结果中可以看出,多维数组和普通数组的存储方式完全一样,也是按次序摆放,只是调用的方式略有不同。

2、结构体
在数组中,所用元素的类型都必须是相同的,为了满足更个性化的需要,就出现了结构体,他是一种类似数组的结构,只不过其内部存储的变量不是单一的数据类型,可以由多种数据类型组成,甚至可以是某个函数。为了表示结构体的这种任意的特性,结构体需要开发者自己编写结构格式,典型结构体的格式定义如下(要放在主函数的前面):
struct student
{
    int number;     //学号
    int age;        //年龄
    double height;  //身高
    char name[8];     //姓名
};//注意分号
该操作只是定义了一个名称为student的框架,并没有实际分配内存。
为了分配内存,我们需要对student结构体进行实例化:
    struct student stu; // 获得student结构体实例stu
    
    // 地址及大小输出
    printf("stu            地址:%p 大小: %lu Byte \n", &stu, sizeof(stu));
    printf("stu.number     地址:%p 大小: %lu Byte \n", &stu.number, sizeof(stu.number));
    printf("stu.age        地址:%p 大小: %lu Byte \n", &stu.age, sizeof(stu.age));
    printf("stu.height     地址:%p 大小: %lu Byte \n", &stu.height, sizeof(stu.height));
    printf("stu.name       地址:%p 大小: %lu Byte \n", &stu.name, sizeof(stu.name));
在上面的方法中,我们通过点语法访问结构体实例的内部变量,并获取各变量的地址,输出结果:
stu            地址:0x7fff5fbff8c0 大小: 24 Byte 
stu.number     地址:0x7fff5fbff8c0 大小: 4 Byte 
stu.age        地址:0x7fff5fbff8c4 大小: 4 Byte 
stu.height     地址:0x7fff5fbff8c8 大小: 8 Byte 
stu.name       地址:0x7fff5fbff8d0 大小: 8 Byte 
可以看出,在结构体实例中,内存的分配是按照内部变量的次序依次排列的,结构体的地址为第一个变量的地址,这和前面的结论一致。

3、共用体
共用体和结构体的创建方法基本相同,所不同的是他的内部变量公用相同的存储单元。为什么要这样做呢?是因为并不是所有的硬件都有足够的内存供我们使用,在有些场合下,一个“结构体”的内部变量同时只用到一个,这时候使用共用体将大大节省内存开支。此外,在通信领域,有时候在接受数据时无法确定数据的类型,先把数据存储下来,然后再根据类型对应读取,举例如下:
创建共用体框架(同样要放在主函数前面):
union reciveData
{
    int number;     // 数字
    char character;  // 字符
};
实例化及验证:
    union reciveData data; // 实例化
    
    // 地址及大小输出
    printf("data                 地址:%p 大小: %lu Byte \n", &data, sizeof(data));
    printf("data.number          地址:%p 大小: %lu Byte \n", &data.number, sizeof(data.number));
    printf("data.character       地址:%p 大小: %lu Byte \n", &data.character, sizeof(data.character));
输出结果:
data                 地址:0x7fff5fbff8d8 大小: 4 Byte 
data.number          地址:0x7fff5fbff8d8 大小: 4 Byte 
data.character       地址:0x7fff5fbff8d8 大小: 1 Byte 
由输出结果可以看出,共用体实例的存储空间为共用体实例内部最大元素的尺寸,各元素的地址相同,都等于共用体的地址。

4、枚举
枚举是一种特殊的数据结构,他将某些固定的数值表示成有意义的标识符,以提高程序的可读性。
枚举和上面的结构体和共用体类似,也需要在主函数前面声明其框架,例如:
enum{spring,summer,autumn,winter}season;//不含类型标签,定义单一的变量
enum color_led{red,green,blue};//含类型标签,可定义多个变量
这两个枚举分别定义了四季和LED灯的三种状态,不同的是,第一个例子中没有“框架名称”,直接声明了单一的枚举,其标识符为season。第二个例子中有 “框架名称“color_led”,我们可以通过此名称创建多个相似的框架。注意,这里并没有分配空间!如果你尝试通过&指令输出地址的话,会报错!
第一个例子的输出:
    printf("spring = %d\n", spring);
    printf("summer = %d\n", summer);
    printf("autumn = %d\n", autumn);
    printf("winter = %d\n", winter);
结果为:
spring = 0
summer = 1
autumn = 2
winter = 3
可见,这些标识符在真正运行的阶段还是以数字的形式进行流通,只是我们给他们换了一个叫发,方便了编程工作及思路的整理。顺便一提的是,我们可以在定义枚举的时候人为的改变这些默认值,方法如下:
enum{
    spring,
    summer = 2,
    autumn,
    winter}season;
此时,summer之后的数据根据summer依次递加,前面的保持不变,输出如下:
spring = 0
summer = 2
autumn = 3
winter = 4

5、总结
合理运用以上几种复杂数据类型,将使我们的程序变得完善和规范,同时便于我们思路的理清。务必弄清楚这几种数据的使用。

-----------Java培训Android培训IOS培训.Net培训期待与您交流!------------ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值