zoukankan      html  css  js  c++  java
  • C/C++(结构体)

    结构体(struct)

    从某种意义上说,会不会使用struct,如何使用struct是区别一个开发人员是否具备丰富开发经验的试金石。
    处理由不同类型成员构成的构造类型,要采用结构体的方式。
    定义:关键字struct.

    无名结构体,一般用于定义类型相同时,定义变量;并且不会带来多余的命名。

    struct{
        char name[40];
        int age;
        int num;
        float score;
    }s1,s2,s3,s4;
    int main() {
        struct{
            char name[40];
            int age;
            int num;
            float score;
        }s1;
        ....
        return 0;
    }
    

    有名结构体

    一处定义各处使用

    struct stu{
        char name[40];
        int age;
        int num;
        float score;
    }
    int main() {
        struct stu s1;
        struct stu s2;
        struct stu s3;
        return 0;
    }
    

    typedef

    对现有类型取别名,不能创造新的类型(typerename)。
    使用方法:

    1.先用原类型定义变量
    2.在定义前加上typedef
    3.将原来的名字改成自己需要的类型名

    typedef char        int8;
    typedef short       int16;
    typedef int         int32;
    typedef long long   int64;
    int main() {
        int8  i8;
        int16 i16;
        int32 i32;
        int64 i64;
        return 0;
    }
    

    别名结构体

    typedef是一个常用于对结构体取别名的关键字,更好的用于结构体中

    typedef struct{
        char name[40];
        int age;
        int num;
        float score;
    }Stu;
    int main() {
        Stu s1;
        Stu s2;
        Stu s3;
    }
    

    typedef与#define区别

    typedef:构成c语言语句参与编译。
    #define构成的语句在预处理阶段处理完毕

    #fefine DINT int
    int main() {
        DINT a,b,c;//所有声明时要替换。
    }
    
    int main() {
        char *p,q;
        printf("sizeof(p) = %d sizeof(q) = %d
    ",sizeof(p),sizeof(q));//4,1
        typedef char * pChar;
        pChar a,b;
        printf("sizeof(a) = %d sizeof(b) = %d
    ",sizeof(a),sizeof(b));//4,4
    
    #define DpChar char *
        DpChar m,n;//<=>char * m,n;
        printf("sizeof(m) = %d sizeof(n) = %d
    ",sizeof(m),sizeof(n));//4,1
    
        return 0;
    }
    

    struct的初始化

    凡是基本类型,既可以在定义的时候初始化,也可以先定义再赋值。
    凡是构造类型,要么在定义的时候初始化,不可以先定义再以实例化的方式赋值。
    初始化是一种特殊的语法,跟赋值不等价。
    成员赋值,不能已初始化的方式赋值(如数组,字符串等)

    struct stu{
        char name[100];
        int num;
        char sex;
        float score;
    }
    
    int main() {
        struct stu s = {"assassin",10001,'f',99};
        //也可以这样赋值
        /*
        struct stu s;
        s.name = "assassin";//错误的,赋值不能这样写,和初始化有区别
        strcpy(s.name,"assassin");
        s.num = 1001;
        ...
        */
        return 0;
    }
    
    struct stu{
        char name[100];
        int num;
        char sex;
        float score;
    }
    int main() {
        struct stu s;
        scanf("%s%d %c%f
    ",s.name,&s.num,&s.sex,&s.score);//其中s.name,name是个数组,数组时个特殊的指针,所以前面不用取址符。&的优先级低于"."的优先级。
        return 0;
    }
    
    

    struct的访问

    一类是访问栈上的,一类是访问堆上的。(点乘员运算符,指向成员运算符)

    #include<stdio.h>
    #include<stdlib.h>
    struct stu{
        char name[100];
        int num;
        char sex;
        float score;
    };
    int main() {
        struct stu s = {"assassin",10001,'f',99};
        struct stu *pa = &s;
        //点乘运算访问
        printf("name   = %s
    ",(*pa).name);
        printf("num    = %d
    ",(*pa).num);
        printf("sex    = %c
    ",(*pa).sex);
        printf("score  = %f
    ",(*pa).score);
    
        printf("======================
    ");
        
        printf("name   = %s
    ",s.name);
        printf("num    = %d
    ",s.num);
        printf("sex    = %c
    ",s.sex);
        printf("score  = %f
    ",s.score);
        //足以说明*pa <=> s
    
    
    //"."点乘优先级高于"*"解引用运算符
        printf("======================
    ");
        //指向成员访问
        printf("name   = %s
    ",pa->name);
        printf("num    = %d
    ",pa->num);
        printf("sex    = %c
    ",pa->sex);
        printf("score  = %f
    ",pa->score);
        return 0;
    }
    /*
    name   = assassin
    num    = 10001
    sex    = f
    score  = 99.000000
    ======================
    name   = assassin
    num    = 10001
    sex    = f
    score  = 99.000000
    ======================
    name   = assassin
    num    = 10001
    sex    = f
    score  = 99.000000
    */
    

    堆上的访问

    typedef struct stu{
        char name[100];
        int num;
        char sex;
        float score;
    }Stu;
    int main() {
        Stu *pa = (Stu*)malloc(sizeof(Stu));
        strcpy(pa->name,"assassin");//赋值
        pa->num = 10001;
        pa->sex = 'f';
        pa->score = 99;
    
        printf("name   = %s
    ",pa->name);
        printf("num    = %s
    ",pa->num);
        printf("sex    = %s
    ",pa->sex);
        printf("score  = %s
    ",pa->score);
    
        free(pa);
        return 0;
    }
    /*
    name   = assassin
    num    = 10001
    sex    = f
    score  = 99.000000
    */
    

    struct赋值

    相同结构体类型的变量间,可以赋值。不同类型不可以。词语发基础奠定了可以用与传参和返值。

    typedef struct stu{
        char name[100];
        int num;
        char sex;
        float score;
    }Stu;
    int main() {
        Stu s;
        Stu s2 = {"assassin",1003,'f',99};
        s = s2;
        printf("%s %d %c %f
    ",s.num,s.num,s.sex,s.score);//是可以赋值的
    
        return 0;
    }
    

    结构体支持赋值,访问和数组一样

    typedef struct _stu{
        char name[10];
    }Stu;
    typedef struct _array{
        int arr[10];
    }Array;
    int main() {
        int arr[10] = {1,2,23,4,5,6,78,};
        int arr2[10];
        arr2 = arr;//error
        Stu stu1 = {"assassin"};
        Stu stu2;
        stu2 = stu1;//正确
    
        Array arr3 = {1,2,23,4,5,6,7,8};
        Array arr4;
        arr4 = arr3;//和上面有区别
        for(int i = 0;i<10;i++) {
            printf("%d
    ",arr4.arr[i]);
        }
    }
    

    传参和返回值的本质就是依次赋值

    typedef struct _complex{
        float real;
        float image;
    }MyComplex;
    //实现一个函数,实现两个负数相加
    MyComplex addComplex(MyComplex x,MyComplex y) {
        MyComplex t;
        t.real = x.real + y.real;
        t.image = x.image + y.image;
        return t;
    }
    int main() {
        MyComplex c1 = {1,2};
        MyComplex c2 = {3,4};
        MyComplex retc = addComplex(c1,c2);
    
        printf("(%.2f,%.2f)
    ",retc.real,retc.image);
    
        return 0;
    }
    //(4.00,6.00)
    

    C语言对于数组的处理就是指针,对于结构体也推荐传指针。(即使有很大的数据,只传4个字节,而且效率提高了很大)

    typedef struct _complex{
        float real;
        float image;
    }MyComplex;
    //实现一个函数,实现两个负数相加
    MyComplex addComplex(MyComplex *px,MyComplex *py) {
        MyComplex t;
        t.real = px->real + py->real;
        t.image = px->image + py->image;
        return t;
    }
    int main() {
        MyComplex c1 = {1,2};
        MyComplex c2 = {3,4};
        MyComplex retc = addComplex(&c1,&c2);
    
        printf("(%.2f,%.2f)
    ",retc.real,retc.image);
    
        return 0;
    }
    //效率大大提高
    

    结构体数组

    结构体数组的本质:是一维数组,只不过是一维数组中的每一个个成员又是结构体。

    typedef struct _stu{
        int num;
        char name[100];
        char sex;
        float score;
    }Stu;
    int main() {
        Stu s[] = {{1001,"assassin",'f',99},{1002,"Wunworld",'f',89},{1003,"seafwg"},{1004,"intelwisd"}};
        for(int i = 0;i < sizeof(s)/sizeof(*s);i++) {
            printf("num    = %d
    ",s[i].num);
            printf("name   = %s
    ",s[i].nam);
            printf("sex    = %c
    ",s[i].sex);
            printf("score  = %f
    ",s[i].score);
        }
    }
    

    实例投票:现有三位侯选人员,侯选人包含名字和选票数两项,现在 10 人对其投票,每个人限投票一次,投票完毕,打印投票结果,如有名字打错,算作弃权处理。

    typedef struct _candidate{
        char name[30];
        int voteCount;
    }Candidate;
    void disCandidate(Candidate *c,int n,int m);
    int main() {
        //初始化候选人
        Candidate can[3] = {
            {"assassin",0},
            {"wunworld",0},
            {"seafwg",0}
        };    
        int count = 0;
        char buf[1024];
        //是个人选举
        for(int i = 0;i < 10;i++) {
            printf("请你选举自己心中的候选人");
            scanf("%s",buf);
            int flag = 1;
            for(int j = 0;j < 3;j++) {            
                if(!strcmp(buf,can[j].name)) {
                    can[j].voteCount++;
                    flag = 0;
                }
            }
            if(flag != 0) {
                count++;
            }
        }
        disCandidate(can,3,count);
    }
    //显示选举后的选票人
    void disCandidate(Candidate *c,int n,int count) {
        for(int i = 0;i < n;i++) {
            printf("Name:10%s VoteCount:%2d
    ",c[i].name,c[i].voteCount);
        }
        printf("the give up people: %d
    ",count);
        //进行排序
        int idx = 0;
        for(int i = 0;i < n;i++) {
            if(c[i].voteCount > c[idx].voteCount) {
                idx = i;
            }
        }
        printf("恭喜%s获得了选举!
    ",c[idx].name);
    }
    

    结构体的嵌套

    struct _birth {
        int year;
        int month;
        int day;
    };
    
    typedef struct _stu {
        char name[20];
        int num;
        char sex;
        float score;
        struct _birth birth;
        //<=>
        /*struct _birth {
            int year;
            int month;
            int day;
        }birth;*/
    }Stu;
    int main() {
        Stu s = {"assassin",10001,'f',99,{1992,04,15}};
        printf("name  = %s
    ",s.name);
        printf("year  = %d
    ",s.birth.year);
        printf("month  = %d
    ",s.birth.month);
        printf("day    = %d
    ",s.birth.day);
    }
    /*
    name  = assassin
    year  = 1992
    month  = 4
    day    = 15
    */
    

    结构体类型的大小

    类型本身不占空间,类型产生的变量才占空间
    结构体中的每个成员的地址均是可以获得的。

    typedef struct _staff{
        char sex;
        int age;
    }Staff;
    
    int main() {
        Satff s;
        printf("sizeof(Staff) = %d
    ",sizeof(Staff));
        printf("sizeof(s)     = %d
    ",sizeof(s));
        
        printf("&s        = %p
    ",&s);
        printf("&s.sex    = %p
    ",&s.sex);
        printf("&s.age    = %p
    ",&s.age);
        
        return 0;
    }
    /*
    sizeof(Staff) = 8
    sizeof(s)     = 8
    &s        = 0061FEA8
    &s.sex    = 0061FEA8
    &s.age    = 0061FEAC
    */
    
    typedef struct _staff{
        char sex;
        int age;
        short like;
    }Staff;
    
    int main() {
        Staff s;
        printf("sizeof(Staff) = %d
    ",sizeof(Staff));
        printf("sizeof(s)     = %d
    ",sizeof(s));
        
        printf("&s        = %p
    ",&s);
        printf("&s.sex    = %p
    ",&s.sex);
        printf("&s.age    = %p
    ",&s.age);
        printf("&s.like   = %p
    ",&s.like);
        
        return 0;
    }
    /*
    sizeof(Staff) = 12
    sizeof(s)     = 12
    &s        = 0061FEA4
    &s.sex    = 0061FEA4
    &s.age    = 0061FEA8
    &s.like   = 0061FEAC
    */
    

    为什么结构体里面的char,short是4个字节
    sex后面空了三个字节,然后去填age,like后面空了两个字节,sex与age直接空了三个字节。like应该填到那个位置。

    内存对齐

    一个成员变量需要多少个机器周期去读的现象,称为内存不对齐。x实现内存对齐主要原因是牺牲空间换取时间的方法。

    对齐规则

    x86linux默认#pragma(4),window默认#pragma pack(8)。linux最大支持4字节对齐。
    方法:

    1.取pack(n)的值(n=1 2 4 8--),去结构体中类型最大值m,两者取小即为外对齐 大小Y=(m<n?m:n);
    2.将每一个结构体的成员大小与Y比较取较小者为X作为内对其的大小。
    3.所谓按X对齐,即为地址(设起始地址为0)能被X整除的地方开始存放数据。
    4.外部对其原则是依据Y的值(Y的最小整数倍),进行补空操作。

    例如:以上述为例

    typedef struct _staff{
        char sex;
        short num;
        int age;
    }Stu;
    
    1.外对齐:pack(8)默认为8 n=8,则按照1,m=4,即Y=4,----外对齐。(sex与age直接空了三个字节)
    2.内对齐:上述Y=4,与成员大小1,2,4比较取小值(x=1,2,4)---内对齐
    3.按照X对齐:
    0-1 2-4 4-8-----8(外侧是Y的最小整数倍补齐) 
        例如:成员大小1,4,2比较后(X=1,4,2)则:
        0-1 4-8 8-10(10不是Y的最小整数倍取12)---大小为12
        eg:pack(1), n=1,m=4,Y=1,
        成员:1 4 2,则X=1 1 1,
        外对齐:0-1 1-5 5-7(7是1的倍数)---大小为7
    

    eg:

    #pragma pack(4)
    typedef struct _stu{
        char sex;
        double num;
        int age;
    }Stu;
    int main() {
        printf("sizeof(Stu) = %d
    ",sizeof(Stu));
    }
    /*
    sizeof(Stu) = 16
    sizeof(s) = 16
    */
    /*pack(4),n=4,m=8--->Y=4
    成员:1 8 4与Y比较取小者X=1 4 4
    0-1 4(能与X整除放成员个大小)-12 12-16-----大小为16
    */
    
    

    结构体注意事项

    typedef struct _stu{
        char name[20];
        int score;
    }Stu;
    int main() {
        Stu s;
        strcpy(s.name,"bob");
        s,score = 99;
    }
    
    
    typedef struct _stu{
        char *name;
        int score;
    }Stu;//只有8个字节,name未初始化
    int main() {
        Stu s;
        strcpy(s.name,"bob");//Error 会挂机
        s.name = (char*)malloc(100);//解决办法放在堆上
        strcpy(s.name,"jim");
        printf("name = %s score = %d
    ",s.name,s.score);
        free(s.name);//必须要释放
        s.score = 99;
    }
    

    申请空间的时候从外至内,释放空间的时候从内之外。

    typedef struct _stu{
        char *name;
        int score;
    }Stu;//只有8个字节,name未初始化
    int main() {
        Stu *ps = (Stu *)malloc(sizeof(Stu));//ps实在栈上申请了8,结构体在堆上,没有初始化。并没有指向。解决办法,再次申请一个堆空间存放地址
        ps->name = (char*)malloc(100);
        strcpy(ps->name,"assassin");
        ps->score = 200;
        printf("name = %s score = %d
    ",ps->name,ps->score);
        free(ps->name);//
        free(ps);
        return 0;
    }
    
    

    数据类型:内存是以字节为单位进行线性编址的硬件基础,对内存进行格式化。

  • 相关阅读:
    Distinct Substrings(spoj 694)
    Musical Theme
    Milk Patterns(poj 3261)
    Repeated Substrings(UVAlive 6869)
    喵星球上的点名(bzoj 2754)
    滑雪与时间胶囊(bzoj 2753)
    莫比乌斯函数之和(51nod 1244)
    欧拉函数之和(51nod 1239)
    数表(bzoj 3529)
    欧拉函数模板
  • 原文地址:https://www.cnblogs.com/intelwisd/p/8326098.html
Copyright © 2011-2022 走看看