zoukankan      html  css  js  c++  java
  • C语言复合数据类型

           C语言数据类型非常丰富,其中结构体的使用非常广泛,也有一点复杂,这一讲我们主要学习结构体的使用方法,同时也会学习到联合、枚举以及typedef的使用,因为结构体最为复杂,使用最广,所以我们主要学习结构体。

    struct结构体的定义和初始化

    //例:
    struct student{
    char name[100];
    int age;
    };
    int main(){
    struct student st;
    //定义了一个student类型的结构体,名字叫做st,存放在栈里边
    st.age =20;
    strcpy(st.name,”liudehua”);
    struct student st1 ={“zhzdu”,40};
    //定义结构体变量,同时初始化结构体变量
    struct student st1 ={.age =40,.name=”zxjiifuhg”};
    //定义结构体变量,同时初始化结构体变量,使用这种方式可以改变初始化顺序
    struct student st1 ={“zhzdu”};
    //定义结构体变量,同时初始化结构体变量,不初始化的结构体变量则默认为0
    };

    结构体的对齐说明

         结构体在内存中总是对齐的,一个结构体成员变量总是以最大的那个元素作为对齐单位。

    struct A{//8字节,a1后面空着3个字节,a2占4个字节
    char a1; 
    int a2;
    }
    struct A1{//8字节,a1后面空着一个字节,然后a3占两个字节,a2占4个字节
    char a1;
    short a3;
    int a2;
    }
    struct A2{
    char a[10];
    int b; 
    }

           如果结构体出现数组,则以数组中的具体每个成员大小为对齐标准,如果变量结构体中的所有成员都是一种类型,那么结构体在内存中就基本和一个数组类似。结构体变量的地址就是它首元素的地址。

    结构体元素的位字段

          为了节省内存空间,结构体变量允许使用为声明,例子如下:

    struct A2{//一共占1字节
    unsigned char a:2;//a只有两个bit
    unsigned char b:4;  //b只有4个bit
    }

    结构体数组

    struct A2{
    char name[20];
    unsigned char age; 
    unsigned char sex;
    }
    void main(){
    struct A2 st[3];//定义一个结构体数组,有3个成员,每个成员都是struct结构体变量
    }

           CPU处理int相比其它基本数据类型效率是最高的,但是int比char要多占内存.

    冒泡排序结构体数组

           首先要学会使用冒泡排序,然后根据结构体某个成员大小之间作比较,再根据冒泡排序交换结构体中的各个成员来排序,具体的实现方法可自行实现。

    结构体嵌套

           结构体内部可以有其它结构体,其本质和结构体没有太多区别。

    struct A{
    char a1;
    short a2;
    };
    
    struct B{
    struct A a;//这里是一个结构体的嵌套
    char a3;//上面结构体变量作为一个整体存在,a3 不可能补到结构体A a2的后面去,它一定是一个单独的对齐单位。
    int b;
    };
    struct D{};//D结构体不含有任何结构体变量,这个语法在C语言是不合法的,在C++里是合法的

            结构体的赋值其实就是内存的拷贝

    struct A{
       char a1;
       short a2;
    };
    struct A st1={s ,s};
    struct A st2=st1;
    //通过指针访问结构体成员
    struct A  * p=&st1;
    //(*p).a1 =12;这种写法与下面写法作用相同,但下面写法更直观
    p->a1 = 12;

    通过指针访问结构体数组

               这个和通过指针去访问数组是类似的,这儿就不详细介绍了

    void main(){
    struct A2 st[3]={0};
    struct A2 *p=st;
    p[1].name = “zcxc”
    }

    结构体中的数组成员和指针成员

    struct man{
    char * name;
    int age;
    };

           结构体拷贝的时候存在浅拷贝与深拷贝;浅拷贝之间只是成员之间的粗暴赋值,解决不了结构体中存在指针时,两个指针成员之间只是简单的地址赋值,当一个结构体变量指针成员释放空间时,另一个结构体变量指针成员访问的空间也就消失了,两结构体变量之间相互影响很大。深拷贝则是存在指针变量时,首先为指针变量各自分配空间,然后再进行拷贝,每个结构体指针变量指向的的空间时相互独立的。

    堆中创建结构体变量

    struct man{
    char  name[20];
    int age;
    };
    struct student{
    char * name;
    int age;
    }
    int main(){
    struct man st;//name在栈里边
    struct man *st1 = malloc(sizeof(struct man));//name在堆里边
    struct man *p = malloc(sizeof(struct student));//name在堆里边
    p->name = malloc(20);
    strcpy(p->name,”lfsdi”);//申请一个堆空间,st1->name在堆里,但是一个野指针
    st1->age = 20;
    free(p->name);
    free(p);//如果结构体变量里含有指针,注意free的先后顺序,如果先free p,则p堆已经释放了,就找不到p->name的首地址
    }

    函数的参数为结构体变量

    struct man{
      char  name[20];
      int age;
    };
    printf_student(struct student st){//st是形参,函数调用的时候,在栈里面有一个浅拷贝的过程,如果里边某个成员为数组较大,会出现一个数组拷贝的过程,会消耗大量时间,不利于优化程序
      printf(“%s,%d\n”,st.name,st.age);
    }
    printf_student(const struct student *st) {//st =&st //只是一个简单的结构体地址赋值,效率远远高于上面的,形参很少直接用一个结构体变量,一般放结构体指针
      printf(“%s,%d\n”,st->name,st->age);
    }

    联合体

           联合union是一个能在同一个存储空间存储不同类型的数据,联合体所占的内存长度等于其最长成员的长度,所以代码效率很高。联合体虽然有多个成员,但同一时间只能存放其中一种。

    union A{
    int a1;
    short a2;
    char a3;
    char *p;
    };//只占4个字节
    int main(){
    union A a;
    a1 =1;
    a3 =10;
    a1 =0; //之后a.a3的值为0
    a.p = malloc(10);//假设这块堆的内存编号为0x12345C
    a.a1 = 0;//p的值也成了0
    free(a.p);
    return 0;
    }

    枚举类型

         可以使用枚举声明代表整数常量的符号名称,关键字enum创建一个新的枚举类型,实际上enum常量是int类型的,可以增加代码的可读性。

    struct A2{
    char name[20];
    unsigned char age; 
    unsigned char sex;
    }
    
    enum color{red,blue,yellow,green,black};
    enum sex {man,woman};
    void main(){
    struct A2 st;
    enum sex s;
    s =man;
    strcpy(st.name,”znfysry”);
    st.sex = man;//man就是一个整形的常量,不能做左值,常量也不能取地址
    st.age = 0;
    }

           每一个枚举都有默认值0,1, 2,3,4,5,6……… 可以自己设置每个成员的值,enum color{red = 100,blue =12,red = 58,yellow,black,white};100,12,58,59,60,61.....,100 在系统内是由CPU产生的一个立即数,不能取地址, “hello”在内存的常量区里,可以取地址,int a =100;//CPU生成一个立即数,在栈中分配一个4个字节的空间,然后把这个空间的值设置为100,enum在编译完成后只是一个不存在于内存中的立即数,不能取地址。

    typdef数据类型

          typdef数据类型是一种高级数据类型,它能使某种类型创建自己的名字。仅限于数据类型,不能是表达式或具体的值。

    struct student{
        char name[20];
        unsigned char age; 
        unsigned char sex;
    }
    typedef struct student M;//M就类似于int,就是一种数据类型
    typedef unsigned char BYTE;//多了一种数据类型叫byte.可以提高代码的维护性
    int main(){
    M m;
    BYTE a;
    return 0;
    }

            typdef数据类型不是一种必须使用的数据类型,但是使用typedef主要目的是为了让程序的可读性更高,方便代码的维护,在代码十分庞大的时候这种数据类型就显得十分必要。

    #ifndef UNICODE  //方便维护代码
    typedef wchar_t TCHAR
    #else
    typedef char TCHAR
    #endif
    void main(){
    TCHAR a1;
    }
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 黑色星期五
    Java实现 蓝桥杯VIP 算法训练 比赛安排
    Java实现 蓝桥杯VIP 算法训练 比赛安排
    Java实现 蓝桥杯VIP 算法训练 斜率计算
    Java实现 蓝桥杯VIP 算法训练 斜率计算
    Java实现 蓝桥杯VIP 算法训练 整数平均值
    Java实现 蓝桥杯VIP 算法训练 整数平均值
    控件动态产生器(使用RegisterClasses提前进行注册)
    Delphi编写自定义控件以及接口的使用(做了一个TpgDbEdit)
    Log4delphi使用心得
  • 原文地址:https://www.cnblogs.com/latencytime/p/10167509.html
Copyright © 2011-2022 走看看