美文网首页
数据结构

数据结构

作者: labi3285 | 来源:发表于2017-09-14 22:02 被阅读14次

    本节来讨论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、总结

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

    相关文章

      网友评论

          本文标题:数据结构

          本文链接:https://www.haomeiwen.com/subject/msjjsxtx.html