精华内容
参与话题
问答
  • C语言结构体(struct)常见使用方法

    万次阅读 多人点赞 2014-04-14 01:51:57
    基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。 (因为C++和C有共通之处,但是在...

    注意:盗版是不会得到修正和更新的!

     

    今天复习一下struct,顺便挖掘一下以前没注意的小细节:

    基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。

    (因为C++和C有共通之处,但是在结构体上的某些机制又有所不同,所以后边提了一下,不喜欢可以略过)

     

    结构体定义:

     

    第一种:只有结构体定义

    struct stuff{
            char job[20];
            int age;
            float height;
    };

     

    第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义

    //直接带变量名Huqinwei
    struct stuff{
            char job[20];
            int age;
            float height;
    }Huqinwei;

    也许初期看不习惯容易困惑,其实这就相当于:

    struct stuff{
            char job[20];
            int age;
            float height;
    };
    struct stuff Huqinwei;
    

     

    第三种:如果该结构体你只用一个变量Huqinwei,而不再需要用

    struct stuff yourname;

    去定义第二个变量。

    那么,附加变量初始化的结构体定义还可进一步简化出第三种

    把结构体名称去掉,用匿名结构体直接定义一个结构体对象(习惯用对象这词了),这样更简洁,不过也不能定义其他同结构体变量了——除非用typeof。

    struct{
            char job[20];
            int age;
            float height;
    }Huqinwei;

    使用typeof重新利用HU的结构体定义HU3,并且定义指针ptr1,ptr2

    #include <stdio.h>
    
    struct
    {
            char a;
            short b;
            int c;
    }HU;
    
    struct
    {
            char a;
            short b;
            int c;
    }HU2;
    
    int main(){
    
            printf("%ld\n",sizeof(HU));
    
            typeof(HU) HU3;
            printf("%ld\n",sizeof(HU3));
            printf("%ld\n",sizeof(HU2));
            typeof(HU) *ptr1 = &HU;
            typeof(HU) *ptr2 = &HU3;
            ptr2->b = 444;
            printf("%d\n",ptr2->b);
            ptr1 = ptr2;
            printf("%d\n",ptr1->b);
    
    
    }
    

    同样的写法,再定义一个结构体成员HU2,他们的“类型”不同,因为如果类型相同,肯定会报错了,实际并没有报。

    不过内存操作角度,HU2和HU应该没有任何区别,也可以用指针强行更改,前提是确认安全,比如没有不同文件不同平台对齐不兼容这种问题,所以C很万能,也很危险

     

    结构体变量及其内部成员变量的定义及访问:

    绕口吧?要分清结构体变量和结构体内部成员变量的概念。

     

    就像刚才的第二种提到的,结构体变量的声明可以用:

    struct stuff yourname;

    其成员变量的定义可以随声明进行:

       struct stuff Huqinwei = {"manager",30,185};
    

    也可以考虑结构体之间的赋值:

            struct stuff faker = Huqinwei;
    //或    struct stuff faker2;
    //      faker2 = faker;
    打印,可见结构体的每一个成员变量一模一样
    

    如果不使用上边两种方法,那么成员数组的操作会稍微麻烦(用for循环可能好点)

            Huqinwei.job[0] = 'M';
            Huqinwei.job[1] = 'a';
            Huqinwei.age = 27;
            Huqinwei.height = 185;
    

    结构体成员变量的访问除了可以借助符号".",还可以用"->"访问(下边会提)。

     

    引用(C++)、指针和数组:

    首先是引用和指针:

    int main()
    {
            struct stuff Huqinwei;
    
            struct stuff &ref = Huqinwei;
            ref.age = 100;
            printf("Huqinwei.age is %d\n",Huqinwei.age);
            printf("ref.age is %d\n",ref.age);
    
            struct stuff *ptr = &Huqinwei;
            ptr->age = 200;
            printf("Huqinwei.age is %d\n",Huqinwei.age);
            printf("ptr->age is %d\n",ptr->age);
    //既然都写了,把指针引用也加上吧
            struct stuff *&refToPtr = ptr;
            refToPtr->age = 300;
            printf("Huqinwei.age is %d\n",Huqinwei.age);
            printf("refToPtr->age is %d\n",refToPtr->age);
    
    
    }
    

     

    更正:之前给引用的初始化语句写错了,而且没注明引用是纯C中没有的东西(在这么个以C为幌子的博客中)。

    引用是C++特有的一个机制,必须靠编译器支撑,至于引用转换到C中本质是什么,我有个帖子写过
     

     

    结构体也不能免俗,必须有数组:

    struct test{
            int a[3];
            int b;
    };
    //对于数组和变量同时存在的情况,有如下定义方法:
            struct test student[3] =      {{{66,77,55},0},
                                            {{44,65,33},0},
                                            {{46,99,77},0}};
    //特别的,可以简化成:
            struct test student[3] =       {{66,77,55,0},
                                            {44,65,33,0},
                                            {46,99,77,0}};
    

     

    变长结构体

    可以变长的数组

    #include <stdio.h>
    #include <malloc.h>
    #include <string.h>
    typedef struct changeable{
            int iCnt;
            char pc[0];
    }schangeable;
    
    main(){
            printf("size of struct changeable : %d\n",sizeof(schangeable));
    
            schangeable *pchangeable = (schangeable *)malloc(sizeof(schangeable) + 10*sizeof(char));
            printf("size of pchangeable : %d\n",sizeof(pchangeable));
    
            schangeable *pchangeable2 = (schangeable *)malloc(sizeof(schangeable) + 20*sizeof(char));
            pchangeable2->iCnt = 20;
            printf("pchangeable2->iCnt : %d\n",pchangeable2->iCnt);
            strncpy(pchangeable2->pc,"hello world",11);
            printf("%s\n",pchangeable2->pc);
            printf("size of pchangeable2 : %d\n",sizeof(pchangeable2));
    }

    运行结果

    size of struct changeable : 4
    size of pchangeable : 4
    pchangeable2->iCnt : 20
    hello world
    size of pchangeable2 : 4

    如上,本例中变长结构体本身长度就是一个int的长度(这个int值通常只为了方便表示后边的数组长度),而后边的数组长度不计算在内,但是该数组可以直接使用。

    (说后边是个指针吧?指针也占长度!这个是不占的!原理很简单,这个东西完全是数组后边的尾巴,malloc开辟的是一片连续空间。其实这不应该算一个机制,感觉应该更像一个技巧吧

    20191113:这块可能有点抽象?建议去了解一下手动开辟空间malloc和指针相关知识,所谓“变长结构体”,不是一个你理解的结构体!至少不是按正常结构体用的,他像是一个逻辑性的概念,空间是malloc开辟的,结构体是以指针形式存在的“虚拟”的概念,简单说,这个“结构体”不在栈空间!

     

     

    20160405补充:

    非弹性数组不能用"char a[]"这种形式定义弹性(flexible)变量,必须明确大小。

    弹性数组在结构体中,下面的形式是唯一允许的:

     

    struct s
    {
            int a;
            char b[] ;
    };

    顺序颠倒会让b和a数据重合,会在编译时不通过。

    char b[] = "hell";也不行(C和C++都不行)

    少了整型变量a又会让整个结构体长度为0,compiler不允许编译通过!不同的是,其实C++形式上是允许空结构体的,本质上是通过机制避免了纯空结构体和类对象,自动给空结构体对象分配一个字节(sizeof()返回1)方便区分对象,避免地址重合!所以呢,C如果有空结构体,定义两个(或一打,或干脆一个数组)该结构体的变量(对象),地址是完全一样的!·!!!!!!!!调试看程序运行,这些语句其实都被当屁放了,根本没有运行,没有实际意义,C压根不支持空结构体这种东西(或者说我也没想好什么场合有用)

     

    struct s2
    {
    //      char a[]  = "hasd" ;
    //      int c;
    };
    int main()
    {
            struct s2 s22;
            struct s2 s23;
            struct s2 s24;
            struct s2 s25;
    }
    


    例外的是,C++唯独不给带弹性数组的结构体分配空间(可能怕和变长结构体机制产生某种冲突,比如大小怎么算):

    struct s
    {
            char b[] ;
    };

     

    struct s
    {
    //        char b[] ;
    };

    C++中两者是不一样的,空的结构体反而“大”(sizeof()返回1)
     

    20160321补充:这个机制利用了一个非常重要的特性——组和指针的区别!数组和指针在很多操作上是一样的,但是本质不一样。最直观的,指针可以改指向,数组不可以,因为数组占用的每一个内存地址都用来保存变量或者对象,而指针占用的内存地址保存的是一个地址,数组没有单独的保存指向地址的这样一个结构。数组的位置是固定的,正如指针变量自身的位置也是固定的,改的是指针的值,是指向的目标地址,而因为数组不存储目标地址,所以改不了指向。企图把地址强制赋值给数组的话,也只是说把指针赋值给数组,类型不兼容。

     

    结构体嵌套:

    结构体嵌套其实没有太意外的东西,只要遵循一定规律即可:

     

    //对于“一锤子买卖”,只对最终的结构体变量感兴趣,其中A、B也可删,不过最好带着
    struct A{ 
            struct B{
                 int c;
            }
            b;
    }
    a;
    //使用如下方式访问:
    a.b.c = 10; 
    

    特别的,可以一边定义结构体B,一边就使用上:

    struct A{
            struct B{
                    int c;
            }b;
    
            struct B sb;
    
    }a;
    

    使用方法与测试:

            a.b.c = 11;
            printf("%d\n",a.b.c);
            a.sb.c = 22;
            printf("%d\n",a.sb.c);
    结果无误。 

    但是如果嵌套的结构体B是在A内部才声明的,并且没定义一个对应的对象实体b,这个结构体B的大小还是不算进结构体A中。

     

     

    结构体与函数:

    关于传参,首先:

    void func(int);
    func(a.b.c);

    把结构体中的int成员变量当做和普通int变量一样的东西来使用,是不用脑子就想到的一种方法。

     

    另外两种就是传递副本和指针了 :

    //struct A定义同上
    //设立了两个函数,分别传递struct A结构体和其指针。
    void func1(struct A a){
            printf("%d\n",a.b.c);
    }
    void func2(struct A* a){
            printf("%d\n",a->b.c);
    }
    main(){
            a.b.c = 112;
            struct A * pa;
            pa = &a;
            func1(a);
            func2(&a);
            func2(pa);
    }
    
    

     

    注意:盗版是得不到更新迭代的(手动滑稽)https://blog.csdn.net/huqinweI987/article/details/23625823

     

     

    占用内存空间:

    struct结构体,在结构体定义的时候不能申请内存空间,不过如果是结构体变量,声明的时候就可以分配——两者关系就像C++的类与对象,对象才分配内存(不过严格讲,作为代码段,结构体定义部分“.text”真的就不占空间了么?当然,这是另外一个范畴的话题)。

     

    结构体的大小通常(只是通常)是结构体所含变量大小的总和,下面打印输出上述结构体的size:

            printf("size of struct man:%d\n",sizeof(struct man));
            printf("size:%d\n",sizeof(Huqinwei));
    结果毫无悬念,都是28:分别是char数组20,int变量4,浮点变量4. 

     

    下边说说不通常的情况:

    对于结构体中比较小的成员,可能会被强行对齐,造成空间的空置,这和读取内存的机制有关,为了效率。通常32位机按4字节对齐,小于的都当4字节,有连续小于4字节的,可以不着急对齐,等到凑够了整,加上下一个元素超出一个对齐位置,才开始调整,比如3+2或者1+4,后者都需要另起(下边的结构体大小是8bytes),相关例子就多了,不赘述。

    struct s
    {
    char a;
    short b;
    int c;
    }

    相应的,64位机按8字节对齐。不过对齐不是绝对的,用#pragma pack()可以修改对齐,如果改成1,结构体大小就是实实在在的成员变量大小的总和了。
    补一个代码,压入1字节对齐,定义s,然后弹出,使用默认,定义s2,两个结构体大小分别为7和8

    #include <stdio.h>
    #pragma pack(push,1)
    struct s
    {
            char a;
            short b;
            int c;
    };
    #pragma pack(pop)
    struct s2
    {
            char a;
            short b;
            int c;
    };
    
    
    
    int main(){
    
            printf("%ld\n",sizeof(struct s));
            printf("%ld\n",sizeof(struct s2));
    
    }
    
    $ ./a.out
    7
    8
    

     

    和C++的类不一样,结构体不可以给结构体内部变量初始化,。

    如下,为错误示范:

     

    #include<stdio.h>
    //直接带变量名Huqinwei
    struct stuff{
    //      char job[20] = "Programmer";
    //      char job[];
    //      int age = 27;
    //      float height = 185;
    }Huqinwei;
    

     

    PS:结构体的声明也要注意位置的,作用域不一样。

    C++的结构体变量的声明定义和C有略微不同,说白了就是更“面向对象”风格化,要求更低。

     

    那么熟悉了常用方法,都要注意哪些常犯错误呢,见C语言结构体常见错误

     

     

     

    展开全文
  • c语言基础语法六——结构体(完结)

    万次阅读 多人点赞 2016-12-24 14:47:25
    关于c语言结构体的引入; 在前面已经介绍了整形(int,long,….),浮点型(flaot,double),字符型(char),还介绍了数组(存储一组具有相同类型的数据),字符串。但是在实际问题中只有这些数据类型是不够的,...

    1;关于c语言结构体的引入;
    在前面已经介绍了整形(int,long,….),浮点型(flaot,double),字符型(char),还介绍了数组(存储一组具有相同类型的数据),字符串。但是在实际问题中只有这些数据类型是不够的,有时候我们需要其中的几种一起来修饰某个变量,例如一个学生的信息就需要学号(字符串),姓名(字符串),年龄(整形)等等,这些数据类型都不同但是他们又是表示一个整体,要存在联系,那么我们就需要一个新的数据类型。
    ——结构体,他就将不同类型的数据存放在一起,作为一个整体进行处理。

    2;c语言使用结构体变量进一步加强了表示数据的能力。
    2.1;结构体声明;

    //申明一个结构体 
    struct book 
    {
        char title[MAXTITL];//一个字符串表示的titile 题目 ; 
        char author[MAXAUTL];//一个字符串表示的author作者 ; 
        float value;//一个浮点型表示的value价格; 
    };//注意分号不能少,这也相当于一条语句; 

    这个声明描述了一个由两个字符数组和一个float变量组成的结构体,但是注意,他并没有创建一个实际的数据对象,而是描述了一个组成这类对象的元素,【因此,我们也有时候将结构体声明叫做模板,因为它勾勒出数据该如何存储,并没有实例化数据对象】。
    下面介绍一下上面的结构体声明;
    1,首先使用关键字struct,他表示接下来是一个结构体。
    2;后面是一个可选的标志(book),它是用来引用该结构体的快速标记。因此我们以后就会可以这样创建数据对象

    struct book library;//把library设为一个可以使用book结构体的结构体变量,则library这个变量就包含了其book结构体中的所有元素

    3;接下来就是一个花括号,括起了结构体成员列表,及就是每个成员变量,使用的都是其自己的声明方式来描述,用分号来结束描述;
    列如;char title[MAXTITL];字符数组就是这样声明的,用分号结束;
    注意;其中每个成员可以使用任何一种c数据结构甚至是其他的结构体,也是可以的;

    4;在结束花括号后的分号表示结构体设计定义 的结束。

    2.2,关于其struct声明的位置,也就是这段代码要放到哪里。同样这也是具有作用域的。
    这种声明如果放在任何函数的外面,那么则可选标记可以在本文件中,该声明的后面的所有函数都可以使用。如果这种声明在某个函数的内部,则它的标记只能咋内部使用,并且在其声明之后;
    这里写图片描述
    这里写图片描述

    2.3;关于我们不断说的,标记名是可选的,那么我们什么时候可以省略,什么时候一定不能省略呢?
    如果是上面那种声明定义的方法,并且想在一个地方定义结构体设计,而在其他地方定义实际的结构体变量那么就必须使用标记;
    可以省略,设计的同时就创建该结构体变量,但是这种设计是一次性的,
    还有就是引入typedef。
    这个到后面的定义结构体变量一起说吧?

    关于结构体类型的定义的总结;
    一般格式就是;
    struct 结构体名(也就是可选标记名)
    {
        成员变量;
    };//使用分号表示定义结束;

    3;定义结构体变量;
    3.1;之前我们结构体类型的定义(结构体的声明)只是告诉编译器该如何表示数据,但是它没有让计算机为其分配空间。我们要使用结构体,那么就需要创建变量,也就是结构体变量;
    创建一个结构体变量;struct book library;
    看到这条指令,编译器才会创建一个结构体变量library,此时编译器才会按照book模板为该变量分配内存空间,并且这里存储空间都是以这个变量结合在一起的,这也是后面访问结构体变量成员的时候,我们就要用到结构体变量名来访问。
    分析;
    struct book的作用;在结构体声明中,struct book所起到的作用就像int,,,,等基础数据类型名作用一样。
    struct book s1,s2,*ss;
    定义两个struct book结构体类型的结构体变量,还定义了一个指向该结构体的指针,其ss指针可以指向s1,s2,或者任何其他的book结构体变量。
    其实;
    struct book library;
    等效于;
    struct book{
    char …
    ….
    …..
    }librar;
    这两种是等效的,只是第一种可以减少代码的编写量;
    3.2;现在还是回到刚才提及的那个问题,可选标志符什么时候可以省略;

    其一;
    struct
    {
        char title[MAXTITL]; 
        char author[MAXAUTL];
        float value; 
    }library;
    //注意这里不再是定义声明结构体类型,而是直接创建结构体变量了,这个编译器会分配内存的;
    //这样的确可以省略标识符也就是结构体名,但是只能使用一次;因为这是;声明结构体的过程和定义结构体变量的过程和在了一起;并且个成员变量没有初始化的;
    //如果你想多次使用一个结构体模块,这样子是行不通的;

    其二;

    typedef定义新类型名来代替已有类型名,即给已有类型重新命名;
    一般格式为;typedef 已有类型 新类型名;
    typedef int Elem; 
    typedef struct{
        int date;
        .....
        .....
    }STUDENT;
    STUDENT stu1,stu2;

    这里写图片描述

    总结一下关于结构体变量的定义;
    1;先定义结构体类型后再定义结构体变量;
    格式为;struct 结构体名 变量名列表;
    struct book s1,s2,*ss;//注意这种之前要先定义结构体类型后再定义变量;
    2;在定义结构体类型的同时定义结构体变量;
    格式为;
    struct 结构体名
    {
    成员列表;
    }变量名列表;//这里结构体名是可以省的,但尽量别省;
    struct book
    {
        char title[MAXTITL];//一个字符串表示的titile 题目 ; 
        char author[MAXAUTL];//一个字符串表示的author作者 ; 
        float value;//一个浮点型表示的value价格;
    }s1,s2;
    3,直接定义结构体类型变量,就是第二种中省略结构体名的情况;
    这种方式不能指明结构体类型名而是直接定义结构体变量,并且在值定义一次结构体变量时适用,无结构体名的结构体类型是无法重复使用的,也就是说,后面程序不能再定义此类型变量了,除非再写一次重复的struct落、

    4;对于结构体变量的初始化;
    4.1;先回忆一下关于基本数据类型和数组类型的初始化;
    int a = 0;
    int array[4] = {1,2,3,4};//每个元素用逗号隔开
    回忆一下数组初始化问题;
    这里写图片描述
    再回到结构体变量的初始化吧?
    关于结构体变量的初始化与初始化数组类似;
    也是使用花括号括起来,用逗号分隔的初始化好项目列表,注意每个初始化项目必须要和要初始化的结构体成员类型想匹配,

    struct book s1={//对结构体初始化 
            "yuwen",//title为字符串 
            "guojiajiaoyun",//author为字符数组 
            22.5    //value为flaot型 
        };
        //要对应起来,用逗号分隔开来,与数组初始化一样;

    4.2;加入一点小知识;
    关于结构体初始化和存储类时期的问题;
    如果要初始化一个具有静态存储时期的结构体,初始化项目列表中的值必须是常量表达式,
    如果存储时期是自动的,那么列表的值就不必是常量了;
    关于这点在讲存储类时期的时候在分析;
    4.3;注意如果在定义结构体变量的时候没有初始化,那么后面就不能全部一起初始化了;
    意思就是;

    /////////这样是可以的,在定义变量的时候就初始化了;
    struct book s1={//对结构体初始化 
            "guojiajiaoyun",//author为字符数组 
              "yuwen",//title为字符串 
              22.5
        };
    /////////这种就不行了,在定义变量之后,若再要对变量的成员赋值,那么只能单个赋值了;
    struct book s1;
        s1={ 
             "guojiajiaoyun",//author为字符数组 
              "yuwen",//title为字符串 
              22.5  
        };//这样就是不行的,只能在定义的时候初始化才能全部赋值,之后就不能再全体赋值了,只能单个赋值;
        只能;
        s1.title = "yuwen";........//单个赋值;
    

    4.4;对于结构体的指定初始化;
    《这个只存在于c99,》
    这里写图片描述

    5;访问结构体成员;
    5.1,结构体就像一个超级数组,在这个超级数组内,一个元素可以是char类型,下个元素就可以是flaot类型,再下个还可以是int数组型,这些都是存在的。在数组里面我们通过下标可以访问一个数组的各个元素,那么如何访问结构体中的各个成员呢?
    用结构成员运算符点(.)就可以了;
    结构体变量名.成员名;
    注意,点其结合性是自左至右的,它在所有的运算符中优先级是最高的;
    例如,s1.title指的就是s1的title部分,s1.author指的就是s1的author部分,s1.value指的就是s1的value部分。然后就可以像字符数组那样使用s1.title,象使用float数据类型一样使用s1.value;
    注意,s1;虽然是个结构体,但是s1.value却是float型的,因此s1.value就相当于float类型的变量名一样,按照float类型来使用;
    例如;printf(“%s\n%s\n%f”,s1.title,s1.author,s1.value);//访问结构体变量元素
    注意scanf(“%d”,&s1.value); 这语句存在两个运算符,&和结构成员运算符点,按照道理我们应该将(s1。value括起来,因为他们是整体,表示s1的value部分)但是我们不括起来也是一样的,因为点的优先级要高于&。
    5.2;如果其成员本身又是一种结构体类型,那么可以通过若干个成员运算符,一级一级的找到最低一级成员再对其进行操作;
    结构体变量名.成员.子成员………最低一级子成员;

    struct date
    {
        int year;
        int month;
        int day;
    };
    struct student
    {
        char name[10];
        struct date birthday;
    }student1;
    //若想引用student的出生年月日,可表示为;student.brithday.year;
    brithday是student的成员;year是brithday的成员;

    5.3;整体与分开
    5.3.1;可以将一个结构体变量作为一个整体赋值给另一相同类型的结构体变量,可以到达整体赋值的效果;这个成员变量的值都将全部整体赋值给另外一个变量;
    5.3.2;不能将一个结构体变量作为一个整体进行输入和输出;在输入输出结构体数据时,必须分别指明结构体变量的各成员;
    这里写图片描述

    总结;除开“相同类型的结构体变量可以相互整体赋值”外,其他情况下,不能整体引用,只能对各个成员分别引用;
    

    6;结构体数组,(这个在国二里面常考的类型,只要考结构体就离不开结构体数组和成员的访问,当然也只是简单的操作)
    6.1;为什么要引用结构体数组,显然,在上面的book类型的结构体 ,每本书就需要用一个book类型的结构体变量来描述,若是要描述两本书,需要使用两个这样的变量,依次类推;因此要使用一个该结构体的数组,来表示这些图书;并且数组就是存储一组具有相同类型的数据,因此就有了结构体数组的出现,注意本置,
    6.2;声明结构体数组
    与普通的数组声明一样,int a[10];int为元素的数据类型,a为数组名 【10】表示申请了10的int单元的内存;
    再看结构体声明;struct book library[10];是不是类似,struct book为数组元素的数据类型,library为数组名,[10]为申请了10个struct book单元的内存;
    解释;声明library为一个具体10个元素的数组,并且每个元素都book类型的结构,因此可以得到library[0],library[1]…….都是单独独立的一个book结构;
    注意library本身不是结构体名而是一个数组名;
    6.4;结构体数组的初始化;
    这里写图片描述
    两种初始化;就是在定义的时候赋值的两种情况;
    6.3;访问结构体数组的成员;
    规则;在结构体名后加点运算符,然后再是成员名;
    library[5].title;//表示第5个元素的title成员;library[5]是结构体变量名,title就是成员名;
    library[5].titlt[4];//注意title是数组类型,第5个数组元素的title成员的第4个字符;

    总结;
    library //book结构体的数组
    library[2]//数组的第二个元素,一个book结构体类型的变量名;
    library[2].title;//char数组,结构体数组的第二个元素的title成员;
    library[2].title[4];//表示一个字符,结构体数组的第二个元素的title成员的第四个字符;

    这里写图片描述

    7;指向结构体的指针,
    7.1;使用指向结构体的好处;就像指向数组的指针一样,它比数组本身更容易操作,指向结构体的指针通常也比结构体本身更容易操作;
    声明和初始化结构体指针,
    声明struct book * him;
    规则就是,struct 结构体名+ * + 指针名;
    这个声明不是建立一个新的结构体,而是创建了一个指针类型的him指针变量,他可以指向任何现有的book类型的结构体;
    him = &library[0];
    指针him正指向结构体library[0],如何使用him来取得library[0]的一个成员呢?
    方法一;
    引入一个运算符,->
    后跟->运算符的结构体指针和后跟.点运算符的结构体名是一样操作的;
    注意一点的是;不能使用him.成语;因为him不是结构体名;

    总结
    ->只用于结构体指针访问成员;
    .点只用于结构体名访问成员;

    方法二;
    如果him=&library[0],那么him=library[0];因为&和是一个互逆的运算符;
    &取地址,*取值;
    =》library[0].value 等价于 (*him).value;注意必须使用圆括号,优先级问题;
    然后都与him.value是一个作用;

    对于考国二懂得上面的也就差不多了;足够了;

    8;向函数传递结构体信息;
    8.1;传递结构体成员;
    只要结构体成员是具有单值的数据类型,(及int等基础数据类型)就可以把它作为参数传递给一个接受这个特定参数类型的函数;
    注意;这个只能实现访问,不能修改;
    8.2;使用结构体地址;
    这里写图片描述
    注意,如果不修改值,则设置为const;
    8.3;使用结构体作为参数传递;
    这里写图片描述
    其中s也是结构体变量,并且为s1结构体变量的副本。
    总结;
    结构体指针,使用->运算符访问成员;
    结构体名;使用.点运算符访问成员;
    要想通过调用函数修改实参结构体变量的值,只能传递地址,通过指针来修改;直在地址上修改;
    8.4;结构体之间的双向通信;
    先注意这个;c语言中对于结构体变量是可以整体赋值的,无论其成员是怎样的;

    传递地址,使用结构体指针接收,用于访问不做修改;const限制修改,

    这里写图片描述

    结构体作为参数传递;不能成功修改实参,只能访问;

    这里写图片描述

    结构体作为参数,修改结构体并且返回类型也为结构体;达到修改的目的;

    这里写图片描述

    传递地址,使用结构体指针接收,用于修改;不使用const限制修改,

    这里写图片描述

    通常我们是使用结构体指针的,如果不修改那么我们会使用const修改;

    9;在结构体中使用字符数组还是字符指针来存储字符串;
    答案先给出,尽量使用字符数组;
    9.1;使用字符数组;

    #define MAXTITL 100
    #define MAXAUTL 100
    struct book 
    {
        char title[MAXTITL];//一个字符串表示的titile 题目 ; 
        char author[MAXAUTL];//一个字符串表示的author作者 ; 
        float value;//一个浮点型表示的value价格; 
    }; 
    字符串的存储在结构体内部的;
    结构体总分配200个字节的内存给这两个字符串

    9.2;使用字符指针;

    struct book 
    {
        char *title; 
        char * author;  
    }; 
    这里的字符串是存储在编译器认为存储字符串常量的任何地方,这个结构体中存放的只有两个地址而已,值分配8分字节;结构体不为字符串分配任何内存存储空间,因此这时候在输入的时候存在了一个潜在的危险;
    scanf("%s",s.last);//把字符串放到由s.last指向的内存中因为这是一个未初始化的变量,因此该地址是可以指向任意大小的,因此此时就是一个潜在的危险;
    

    总结,因我们最好是使用字符数组来存储字符串;

    10;结构体和指针和malloc函数;
    这个可以看我之前的博客;
    http://blog.csdn.net/zw1996/article/details/53708591

    关于结构体的介绍就暂时到这里
    时间有点急,学得也不深,所以暂时先补充到这里,下次补上;
    还有未补充的内容;
    1;结构体数组的函数;
    2;结构体内容保存在文件当中;
    3;一些结构体的例子;

    展开全文
  • C语言结构体详解

    千次阅读 2018-04-24 17:10:56
    结构(struct) &nbsp;&nbsp;&nbsp;&nbsp; 结构是由基本数据类型构成的、并用一个标识符来命名的各种变量的组合。&nbsp; 结构中可以使用不同的数据类型。&nbsp; &... 1....n...
    结构(struct)
         结构是由基本数据类型构成的、并用一个标识符来命名的各种变量的组合。 
    结构中可以使用不同的数据类型。 
        1. 结构说明和结构变量定义 
        在Turbo C中, 结构也是一种数据类型, 可以使用结构变量, 因此,  象其它 
    类型的变量一样, 在使用结构变量时要先对其定义。 
        定义结构变量的一般格式为: 
         struct 结构名 
         { 
              类型  变量名; 
              类型  变量名; 
              ... 
         } 结构变量; 
        结构名是结构的标识符不是变量名。 
        类型为第二节中所讲述的五种数据类型(整型、浮点型、字符型、指针型和 
    无值型)。 
        构成结构的每一个类型变量称为结构成员, 它象数组的元素一样, 但数组中 
    元素是以下标来访问的, 而结构是按变量名字来访问成员的。 
        下面举一个例子来说明怎样定义结构变量。 
         struct string 
         { 
              char name[8]; 
              int age; 
              char sex[2]; 
              char depart[20]; 
              float wage1, wage2, wage3, wage4, wage5; 
         } person; 
        这个例子定义了一个结构名为string的结构变量person,   如果省略变量名 
    person, 则变成对结构的说明。用已说明的结构名也可定义结构变量。这样定义 
    时上例变成: 
         struct string 
         { 
              char name[8]; 
              int age; 
              char sex[2]; 
              char depart[20]; 
              float wage1, wage2, wage3, wage4, wage5; 
         }; 
         struct string person; 
        如果需要定义多个具有相同形式的结构变量时用这种方法比较方便, 它先作 
    结构说明, 再用结构名来定义变量。 
        例如: 
         struct string Tianyr, Liuqi, ...; 
        如果省略结构名, 则称之为无名结构, 这种情况常常出现在函数内部, 用这 
    种结构时前面的例子变成: 
         struct 
         { 
              char name[8]; 
              int age; 
              char sex[2]; 
              char depart[20]; 
              float wage1, wage2, wage3, wage4, wage5; 
         } Tianyr, Liuqi; 
        2. 结构变量的使用 
        结构是一个新的数据类型, 因此结构变量也可以象其它类型的变量一样赋值、 
    运算, 不同的是结构变量以成员作为基本变量。 
        结构成员的表示方式为: 
              结构变量.成员名 
        如果将"结构变量.成员名"看成一个整体,  则这个整体的数据类型与结构中 
    该成员的数据类型相同, 这样就可象前面所讲的变量那样使用。 
        下面这个例子定义了一个结构变量, 其中每个成员都从键盘接收数据, 然后 
    对结构中的浮点数求和, 并显示运算结果, 同时将数据以文本方式存入一个名为 
    wage.dat的磁盘文件中。请注意这个例子中不同结构成员的访问。 
        例3: 
         #i nclude <stdio.h> 
         main() 
         { 
              struct{                  /*定义一个结构变量*/ 
                   char name[8]; 
                   int age; 
                   char sex[2]; 
                   char depart[20]; 
                   float wage1, wage2, wage3, wage4, 
    wage5; 
              }a; 
              FILE *fp; 
              float wage; 
              char c=’Y’; 
              fp="fopen"("wage.dat", "w");    
    /*创建一个文件只写*/ 
              while(c==’Y’||c==’y’)         
    /*判断是否继续循环*/ 
              { 
                   printf("/nName:"); 
                   scanf("%s", a.name);     /*输入姓名*/ 
                   printf("Age:"); 
                   scanf("%d", &a.wage);    /*输入年龄*/ 
                   printf("Sex:"); 
                   scanf("%d", a.sex); 
                   printf("Dept:"); 
                   scanf("%s", a.depart); 
                   printf("Wage1:"); 
                   scanf("%f", &a.wage1);   /*输入工资*/ 
                   printf("Wage2:"); 
                   scanf("%f", &a.wage2); 
                   printf("Wage3:"); 
                   scanf("%f", &a.wage3); 
                   printf("Wage4:"); 
                   scanf("%f", &a.wage4); 
                   printf("Wage5:"); 
                   scanf("%f", &a.wage5); 
                   
    wage=a.wage1+a.wage2+a.wage3+a.wage4+a.wage5; 
                   printf("The sum of wage is 
    %6.2f/n", wage);/*显示结果*/ 
                   fprintf(fp, 
    "%10s%4d%4s%30s%10.2f/n"/*结果写入文件*/ 
                                a.name, a.age, a.sex, 
    a.depart, wage); 
                   while(1) 
                   { 
                        printf("Continue?<Y/N>"); 
                        c="getche"(); 
                        
    if(c==’Y’||c==’y’||c==’N’||c==’n’) 
                             break; 
                   } 
              } 
              fclose(fp); 
         } 
        3. 结构数组和结构指针 
        结构是一种新的数据类型, 同样可以有结构数组和结构指针。 
        一、结构数组 
        结构数组就是具有相同结构类型的变量集合。假如要定义一个班级40个同学 
    的姓名、性别、年龄和住址, 可以定义成一个结构数组。如下所示: 
         struct{ 
              char name[8]; 
              char sex[2]; 
              int age; 
              char addr[40]; 
         }student[40]; 
        也可定义为: 
         struct string{ 
              char name[8]; 
              char sex[2]; 
              int age; 
              char addr[40]; 
         }; 
         struct string student[40]; 
        需要指出的是结构数组成员的访问是以数组元素为结构变量的, 其形式为: 
              结构数组元素.成员名 
        例如: 
          student[0].name 
          student[30].age 
        实际上结构数组相当于一个二维构造, 第一维是结构数组元素, 每个元素是 
    一个结构变量, 第二维是结构成员。 
        注意: 
        结构数组的成员也可以是数组变量。 
        例如: 
         struct a 
         { 
              int m[3][5]; 
              float f; 
              char s[20]; 
         }y[4]; 
        为了访问结构a中结构变量y[2]的这个变量, 可写成 
           y[2].m[1][4] 
        二、结构指针 
        结构指针是指向结构的指针。它由一个加在结构变量名前的"*" 操作符来定 
    义, 例如用前面已说明的结构定义一个结构指针如下: 
         struct string{ 
              char name[8]; 
              char sex[2]; 
              int age; 
              char addr[40]; 
         }*student; 
        也可省略结构指针名只作结构说明, 然后再用下面的语句定义结构指针。 
          struct string *student; 
        使用结构指针对结构成员的访问, 与结构变量对结构成员的访问在表达方式 
    上有所不同。结构指针对结构成员的访问表示为: 
           结构指针名->结构成员 
        其中"->"是两个符号"-"">"的组合, 好象一个箭头指向结构成员。例如要 
    给上面定义的结构中name和age赋值, 可以用下面语句: 
         strcpy(student->name, "Lu G.C"); 
         student->age=18; 
        实际上, student->name就是(*student).name的缩写形式。 
        需要指出的是结构指针是指向结构的一个指针, 即结构中第一个成员的首地 
    址, 因此在使用之前应该对结构指针初始化, 即分配整个结构长度的字节空间, 
    这可用下面函数完成, 仍以上例来说明如下: 
         student=(struct string*)malloc(size of 
    (struct string)); 
        size of (struct string)自动求取string结构的字节长度, 
    malloc() 函数 
    定义了一个大小为结构长度的内存区域, 然后将其诈地址作为结构指针返回。 
        注意: 
        1. 结构作为一种数据类型,  因此定义的结构变量或结构指针变量同样有局 
    部变量和全程变量, 视定义的位置而定。 
        2. 结构变量名不是指向该结构的地址, 这与数组名的含义不同,  因此若需 
    要求结构中第一个成员的首地址应该是&[结构变量名]。 
        4. 结构的复杂形式 
        一、嵌套结构 
        嵌套结构是指在一个结构成员中可以包括其它一个结构, Turbo C 允许这种 
    嵌套。 
        例如: 下面是一个有嵌套的结构 
         struct string{ 
              char name[8]; 
              int age; 
              struct addr address; 
         } student; 
        其中: addr为另一个结构的结构名, 必须要先进行, 说明, 即 
         struct addr{ 
              char city[20]; 
              unsigned lon zipcode; 
              char tel[14]; 
         } 
        如果要给student结构中成员address结构中的zipcode赋值, 则可写成: 
          student.address.zipcode=200001; 
        每个结构成员名从最外层直到最内层逐个被列出, 即嵌套式结构成员的表达 
    方式是: 
          结构变量名.嵌套结构变量名.结构成员名 
        其中: 嵌套结构可以有很多, 结构成员名为最内层结构中不是结构的成员名。 
      
        二、位结构 
        位结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构 
    比按位运算符更加方便。 
        位结构定义的一般形式为: 
         struct位结构名{ 
              数据类型 变量名: 整型常数; 
              数据类型 变量名: 整型常数; 
         } 位结构变量; 
        其中: 数据类型必须是int(unsigned或signed)。 整型常数必须是非负的整 
    数, 范围是0~15, 表示二进制位的个数, 即表示有多少位。 
        变量名是选择项, 可以不命名, 这样规定是为了排列需要。 
        例如: 下面定义了一个位结构。 
         struct{ 
              unsigned incon: 8;  
    /*incon占用低字节的0~7共8位*/ 
              unsigned txcolor: 
    4;/*txcolor占用高字节的0~3位共4位*/ 
              unsigned bgcolor: 
    3;/*bgcolor占用高字节的4~6位共3位*/ 
              unsigned blink: 1/*blink占用高字节的第7位*/ 
         }ch; 
        位结构成员的访问与结构成员的访问相同。 
        例如: 访问上例位结构中的bgcolor成员可写成: 
          ch.bgcolor 
      
        注意: 
        1. 位结构中的成员可以定义为unsigned, 也可定义为signed,  但当成员长 
    度为1时, 会被认为是unsigned类型。因为单个位不可能具有符号。 
        2. 位结构中的成员不能使用数组和指针, 但位结构变量可以是数组和指针, 
    如果是指针, 其成员访问方式同结构指针。 
        3. 位结构总长度(位数), 是各个位成员定义的位数之和,  可以超过两个字 
    节。 
        4. 位结构成员可以与其它结构成员一起使用。 
        例如: 
         struct info{ 
              char name[8]; 
              int age; 
              struct addr address; 
              float pay; 
              unsigned state: 1; 
              unsigned pay: 1; 
              }workers;’ 
        上例的结构定义了关于一个工从的信息。其中有两个位结构成员, 每个位结 
    构成员只有一位, 因此只占一个字节但保存了两个信息, 该字节中第一位表示工 
    人的状态, 第二位表示工资是否已发放。由此可见使用位结构可以节省存贮空间。  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
                                                <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/production/markdown_views-ea0013b516.css">
                                    </div>
    
    展开全文
  • c语言结构体学习整理(结构体初始化,结构体指针)

    万次阅读 多人点赞 2018-11-01 20:22:12
    c语言中交换两个结构体的值(结构体指针) 1关于语言的结构体: 首先我们为什么要用到结构体,我们都已经学了很多int char …等类型还学到了同类型元素构成的数组,以及取上述类型的指针,在一些小应用可以灵活...

    渣渣c的c语言学习之路

    1.关于c语言的结构体:

    首先我们为什么要用到结构体,我们都已经学了很多int char …等类型还学到了同类型元素构成的数组,以及取上述类型的指针,在一些小应用可以灵活使用,然而,在我们实际应用中,每一种变量进行一次声明,再结合起来显然是不太实际的,类如一位学生的信息管理,他可能有,姓名(char),学号(int)成绩(float)等多种数据。如果把这些数据分别单独定义,就会特别松散、复杂,难以规划,因此我们需要把一些相关的变量组合起来,以一个整体形式对对象进行描述,这就是结构体的好处。

    2首先我们要了解一些小知识

    2.1**只有结构体变量才分配地址,而结构体的定义是不分配空间的。**
    2.2结构体中各成员的定义和之前的变量定义一样,但在定义时也不分配空间。
    2.3结构体变量的声明需要在主函数之上或者主函数中声明,如果在主函数之下则会报错
    2.4c语言中的结构体不能直接进行强制转换,只有结构体指针才能进行强制转换
    2.5相同类型的成员是可以定义在同一类型下的
    列如

    
    struct Student
    { 
    	int number,age;//int型学号和年龄
    	char name[20],sex;//char类型姓名和性别
    	float score;
    }

    最后的分号不要忘了 有的编译器会自动加上,因此有的同学就会不注意。

    3关于结构体变量的定义和引用

    在编译时,结构体的定义并不分配存储空间,对结构体变量才按其数据结构分配相应的存储空间

    
     struct Book
     { 
     	char title[20];//一个字符串表
    
    示的titile 题目
    	char author[20];//一个字符串表示的author作者
     	float value;//价格表示 
     };//这里只是声明 结构体的定义 
    struct Book book1,book2;//结构体变量的定义 分配空间
    
    book1.value;//引用结构体变量
    

    定义结构体变量以后,系统就会为其分配内存单元,比如book1和book2在内存中占44个字节(20+20+4)具体的长度你可以在你的编译器中使用sizeof关键字分别求出来。
    列如

    当然,要注意一点:用sizeof关键字求结构体长度时,返回的最大基本类型所占字节的整数倍 比方说我们上面求得的为44 为 float(4个字节)的整数倍,
    但是我们把title修改为title[22]; 这时正常长度为46 ,但是你会发现实际求得的为48,(4的整数倍)

    这就涉及到结构体的存储

    1结构体整体空间是占用空间最大的成员(的类型)所占字节数的整数倍。

    2.结构体的每个成员相对结构体首地址的偏移量(offset)都是最大基本类型成员字节大小的整数倍,如果不是编译器会自动补齐,

    关于这个我们简单介绍下:

    1.偏移量----偏移量指的是结构体变量中成员的地址和结构体变量首地址的差。即偏移字节数,结构体大小等于最后一个成员的偏移量加上他的大小,第一个成员的偏移量为0,

    struct S1
    {
        char a;
    
        int b;
    
        double c;
    };
    

    这里char a 偏移量为1 之后为int b 因为偏移量1不为int(4)的整数倍,所以会自动补齐,而在 double c 时,偏移量为8 是double(8)的整数倍,所以不用自动补齐 最后求得结构体得大小为 16

    具体看下图:
    在这里插入图片描述
    通过上面的代码同学们应该会有一个简单的认知

    4结构体变量的初始化

    结构体的初始化有很多需要注意的地方,这里我们说明下
    首先是几种初始化的方法
    ps在对结构体变量初始化时,要对结构体成员一一赋值,不能跳过前面成员变量,而直接给后面成员赋初值,但是可以只赋值前面几个,对与后面未赋值的变量,如果是数值型,则会自动赋值为0,对于字符型,会自动赋初值为NULL,即‘\0’

    4.1定义时直接赋值

    struct Student
    { 
    	char name[20];
    	char sex;
    	int number;
    }stu1={"zhaozixuan",'M',12345};
    //或者
    struct Student
    { 
    	char name[20];
    	char sex;
    	int number;
    }struct Student stu1={"zhaozixuan",'M',12345};
    
    

    注意字符为‘ ’ 字符串为""
    4.2定义结构体之后逐个赋值

    stu1.name="王伟";
    stu1.sex='M';
    stu1.number=12305;
    //也可用strcpy函数进行赋值
    strcpy(stu1.name,"王伟");
    
    

    4.3定义之后任意赋值

     struct Student stu1={
      .name="Wang",
      .number=12345,
      .sex='W', 
     };//可以对任意变量赋值
    

    这样写的好处时不用按照顺序来进行初始化,而且可以对你想要赋值的变量直接进行赋值,而不想赋值的变量可以不用赋值

    需要注意的是如果在定义结构体变量的时候没有初始化,那么后面就不能全部一起初始化了;

    等下结构体数组初始化时我们还会有一个讲解

    这里我们顺带提一下typedef说明结构体类型


    这里的BOOK就相当于struct book的一个别名一样,用它来定义结构体变量非常简便
    主要也是考二级要用到,所以我们简单介绍下

    5结构体变量的引用(输出和输入)

    5.1结构体变量的赋值用scanf赋值和printf输出时跟其他变量操作一样
    但是有几点需要注意
    (1) .是运算符,在所有运算符优先级中最高
    (2)如果结构体的成员本身是一个结构体,则需要继续用.运算符,直到最低一级的成员。

    struct Student
    {	char name[20];
    	char sex;
    	int number;
    	struct Date
    	{
    		int year;
     		int month;
     		int day;
    	}birthday;
    
    }stu1;
    printf("%d",stu1.birthday);//这样子是错误的,因为birthday也是一个结构体变量
    scanf("%d",&stu1.birthday.month);//正确
    

    (3)可以引用接头体变量成员的地址,也可以引用结构体变量的地址:

    printf("%o", student);(输出student的首地址)(%o 按八进制输出)

    6结构体数组及其初始化(重点)

    这里我们简单说下,具有相同类型的结构体变量组成数组就是结构体数组

    结构体数组与结构体变量区别只是将结构体变量替换为数组

    struct Student
    { 
    	char name[20];
    	char sex;
    	int number;
    }stu1[5]={
    	 {"zhaozixuan",'M',12345},
    	 {"houxiaohong",'M',12306},
    	 {"qxiaoxin",'W',12546},
    	 {"wangwei",'M',14679},
    	 {"yulongjiao",'W',17857}
    };
    stu1[3].name[3]//表示stu1的第三个结构变量中姓名的第五个字符
    //若初始化时已经是结构体数组全部元素[]中的数可以不写如stu1[]=
    

    注意结构体数组要在定义时就直接初始化,如果先定义再赋初值是错误的
    比如:

    struct Student stu1;
    stu1[3]={
      {"zhaozixuan",'M',12345},
      {"houxiaohong",'M',12306},
      {"qxiaoxin",'W',12546}
      };
      
    

    这样子是错误的,

    这里我在写的时候遇到一些问题,还是结构体数组初始化的问题,折腾了下解决了,给大家分享下
    对于数组初始化时
    比如

    char str[20];
    str="I love you";/* 这样会修改数组的地址,但是数组的地址分配之后是不允许改变的 */
    
    

    在第一条语句中 str就已经被定义成数组而在C99标准中不允许将字符串(实际上是一个指针变量) 赋值给数组,所以如果我们直接赋值是错误的

    那么怎么弄呢
    这里提供3种方法

    1.定义数组时直接定义
    char str[20]=“I love you”;

    2.用strcpy或者memset函数进行复制
    char str[20];
    strcpy(str,“I love you”);
    再用到memset函数时,出现了一些问题
    对于memcset函数简单介绍下

    memset
    void *memset(void *s,int c,size_t n)
    作用:将已开辟内存空间s的首n个字节的值设为值c。

    char str[20];
    memset(str,'a',20);
    

    如果是字符类型数组的话,memset可以随便用,但是对于其他类型的数组,一般只用来清0或者填-1,如果是填充其他数据就会出错

    int str[10];
    memset(str,1,sizeof(str));//这样是错误的
    
    

    这里我们说下这个错误,

    首先我们要知道memset在进行赋值时,是按字节为单位来进行赋值的,每次填充的数据长度为一个字节,而对于其他类型的变量,比如int,占4个字节 所以sizeof(str)=40; 而用memset赋值时,将会对指向str地址的前40个字节进行赋值0x01(00000001) 的操作,把0x00000000赋值4次0x01操作变为0x01010101(00000001000000010000000100000001)

    相当于给“前10个int”进行了赋值0x01010101的操作 对应十进制的16843009
    所以会出很大的错误

    这里请务必要注意,但是如果是清零一个数组用memset还是很方便的
    简单使用的话同学们用strcmp函数就行

    3用指针(注意内存分配)
    char *str;
    str=“I love you”;

    这两句话的本质是,在内存中开辟一段内存空间,把"I love you"放进这段内存空间,然后把这段内存空间的地址交给str,由于str是变量,所以给它赋值是合法的。

    请注意,在我们进行数组初始化的时候如果定义的数组过长,而我们只初始化了一部分数据,对于未初始化的数据如果是数值型,则会自动赋值为0,对于字符型,会自动赋初值为NULL,即‘\0’ 即不足的元素补以默认值
    这里我们在4小节中也提到了
    比如

    int str[10]={1};//这里只是把str的第一个元素赋值为1,其他元素默认为0
    
    



    7结构体与指针

    我们知道,指针指向的是变量所占内存的首地址,在结构体中,指针指向的是结构体变量的起始地址,当然也可指向结构体变量的元素
    这里我们分为三部分
    7.1指向结构体变量的指针

    定义形式一般为
    struct 结构体名* 指针名;
    比如: struct Student* p;

    struct Student
    {	
    	char cName[20];
     	int number;
     	char csex;  
    }student1;
    struct Student*p;
    p=&student1;
    //若为结构体数组则
    struct Student stu1[5];
    struct Student*p;
    p=stu1;//因为stu1为结构体数组而p=stu1直接是指向stu1的首地址,就不用再加&符
    
    

    用结构体指针变量访问结构体变量成员有以下两种方式:
    (*p).cName //这里的括号不能少,在5.1中有提到
    p->cName

    简单来说以下三种形式是等价的

    p->cName
    (*p).cName 
    student1.cName
    p->cName //可以进行正常的运算
    

    p->number++; 是将结构体变量中number的值进行运算,然后再加一,
    这里要注意下,等下在7.2中会有比较

    7.2指向结构体数组的指针

    7.1中我们已经提到结构体数组指针的命名,这里我们仅对一些知识点做下介绍
    这里我们接着来说结构体数组指针
    在我们想要用指针访问结构体数组的第n个数据时可以用

    struct Student stu1[5];
    struct Student*p;
    p=stu[n];
    (++p).number//是指向了结构体数组下一个元素的地址
    
    

    7.3结构体成员是指针类型变量
    比如

    struct Student
    {
     	char* Name;//这样防止名字长短不一造成空间的浪费
     	int number;
     	char csex;  
    }student1;
    
    

    在使用时可以很好地防止内存被浪费,但是注意在引用时一定要给指针变量分配地址,如果你不分配地址,结果可能是对的,但是Name会被分配到任意的一的地址,结构体不为字符串分配任何内存存储空间具有不确定性,这样就存在潜在的危险,

    struct Student
    {
     	char* Name;
     	int number;
     	char csex;  
    }stu,*stu;
    
    stu.name=(char*)malloc(sizeof(char));//内存初始化
    

    这里我们说一下,同学们看书的时候一般不会看到,
    如果我们定义了结构体指针变量,他没有指向一个结构体,那么这个结构体指针也是要分配内存初始化的,他所对应的指针类型结构体成员也要相应初始化分配内存

    struct Student
    {
     	char* Name;
     	int number;
    	char csex;  
    }stu,*stu;
    stu = (struct student*)malloc(sizeof(struct student));./*结构体指针初始化*/
      stu->name = (char*)malloc(sizeof(char));/*结构体指针的成员指针同样需要初始化*/  
    
    

    7.4二叉树遍历算法
    二叉树的二叉链表类型定义如下:
    typedef struct btnode {
    datatype data;
    struct btnode *lchild,*rchild;
    };
    这里我们仅仅提出以下,因为涉及到链表,感兴趣的同学可以去学习下(二级要用),
    7.5结构体作为函数参数

    首先我们要注意的一点,使用结构体变量作为函数参数的时候,采取的是值传递的方式,将结构体所占内存单元的内容全部传递给形参,并且形参必须也要是同类型的结构体变量,在使用时,会自动创建一个结构体变量作为原变量的副本,并且也需要占内存,并且在调用期间如果修改(形参)结构体中成员的值,修改值是无效的

    而如果用指针作为实参,传递给函数的形参,这时候传递的是结构体的地址,形参所指向的地址就是结构体变量的地址,这时候进行修改的话是可以修改的,这正是指针的精华所在

    在这里我们再提供几种互换两个结构体的方法

    struct Student
    {
     char cName[20];
     int number;
     char csex;  
    }student1,student2;
    struct Student student1={"Wang",12345,'W'};
    struct Student student2={"Zhao",54321,'M'}; 
    struct Student*stu1=&student1;
    struct Student*stu2=&student2;
    
    struct Student *student3;
    student3=stu1;
    stu1=stu2;
    stu2=student3;//互换地址
    
    2对于同类型结构体直接互换值就行
    struct stu student3;
    student3=student1;
    student1=student2;
    student2=student3;
    //这里也可以写成应strcmp函数互换
    
    3memcpy()函数进行互换
    
    
    4比较笨的方法: 用for循环互换
    

    最后提下memset清空结构体

    struct Student
    {
     char cName[20];
     int number;
     char csex;  
    }stu1;
    
    一般情况下,清空str的方法:
      str.cName[0]='\0';
      str.csex='0';
      str.number=0;
      但是我们用memset就非常方便:
      memset(&str,0,sizeof(struct Student));
      如果是数组:
      struct Student stu[10];
      就是
      memset(stu,0,sizeof(struct Student)*10);
    

    整理不易,点个赞再走呗!

    展开全文
  • C语言中的结构体(struct)

    万次阅读 多人点赞 2015-11-08 13:50:11
    C语言中,结构体类型属于一种构造类型(其他的构造类型还有:数组类型,联合类型)。本文主要介绍关于结构体以下几部分。 1、概念为什么要有结构体?因为在实际问题中,一组数据往往有很多种不同的数据类型。例如,...
  • 浅析C语言中的结构体

    千次阅读 2018-05-26 14:09:05
    结构体:是一系列有相同类型或不同类型构的数据构成的数据集合。结构体的学习可以从以下几个方面开始:一.结构体类型的声明。struct tag{member-list;} vaeriable-list;注:tag 要做到见名知义,可以省略但是不建议...
  • C语言结构体类型的定义和使用(一)

    万次阅读 多人点赞 2019-08-16 16:50:39
    0x00 前言 文章中的文字可能存在语法错误以及标点错误,请谅解; 如果在文章中发现代码错误或其它问题请告知,感谢!...0x01 结构体类型的定义 0x02 结构体类型变量的定义 0x03 结构体类型变量初始化和引用 ...
  • 结构的基础知识 ...tag 是结构体标签。 member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。 variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或
  • C语言结构体学习总结

    万次阅读 多人点赞 2018-08-13 18:04:11
    C语言中包含short、int、long、char、float、double这六中基本数据类型。当然还有构造类型、指针类型、和空类型。如图所示: 今天,我们着重总结一下构造数据类型中的结构体 (关键字:struct,不能省略) 的相关...
  • C语言结构体初始化的四种方法

    万次阅读 多人点赞 2018-03-15 17:17:19
    定义 struct InitMember { int first; double second; char* third; float four; }; 方法一:定义时赋值 struct InitMember test = {-10,3.141590,"...方法二:定义后逐个...
  • C语言 结构体结构体指针用法总结

    万次阅读 多人点赞 2017-08-20 17:03:18
    C语言开发中,结构体用到的机会很多。所谓结构体,就是定义一种里面包含多种元素的变量。 我们来看一个简单的例子。比如你想定义一个书名列表然后为每本书创建书名和作者作为书的信息。结构体变量定义如下: ...
  • 结构体的定义与使用 结构体是一种构造数据类型 把不同类型的数据组合成一个整体 结构体的定义形式: struct 结构体名{ 结构体所包含的变量或数组 }; 结构体是一种集合,它里面包含了多个变量或数组,它们的...
  • C语言结构体链表的排序方法汇总 ========================== 功能:选择排序(由小到大) 返回:指向链表表头的指针 ========================== */ /* 选择排序的基本思想就是反复从还未排好序的那些节点中, ...
  • C语言结构体知识汇总

    2018-01-15 12:28:35
    C语言结构体部分内容详解包括结构体定义及使用,结构体函数的定义及使用,指向结构体的指针
  • c语言结构体用法

    千次阅读 多人点赞 2018-10-08 15:43:51
    结构体(struct) 结构体是由基本数据类型构成的、并用一个标识符来命名的各种变量的组合。结构体中可以使用不同的数据类型。 1. 结构体说明和结构体变量定义 在Turbo C中, 结构体也是一种数据类型, 可以使用...
  • C语言结构体实例

    2019-04-11 17:32:27
    C语言结构体实例,很简单,配套郝斌老师的数据结构
  • C语言 结构体、共用体

    千次阅读 多人点赞 2018-07-21 15:30:15
    C语言 结构体、共用体 一、简述  对结构体、共用体的认识。  结构体是一种自定义的复合数据类型。  类比数组,数组也算一种复合数据类型,数组是由多个由相同数据类型的元素组成,(比如需要记录描述100个人的...
  • c语言结构体和union

    2017-04-08 14:15:40
    c语言结构体定义: 1.先定义结构体数据类型,再声明变量 struct s_name { 成员... }; struct s_name var_name;//声明变量,在c++里struct可以不写。 2.定义结构体类型的同时,声明变量 struct s_name { ...
  • 111
  • c语言 结构体

    千次阅读 多人点赞 2019-10-07 22:55:15
    1. 结构体的使用: 2. 直接声明结构变量: 结构体嵌套:

空空如也

1 2 3 4 5 ... 20
收藏数 109,883
精华内容 43,953
关键字:

c语言结构体

c语言 订阅