构造类型-结构体

2020-04-19  本文已影响0人  晓晓桑

声明结构体

//声明结构体 可以在函数外部,所有方法都可以用
struct Student {
    char name[10];
    unsigned int age;
    double high;
    char num[20];
};

int main(void) {

    //声明结构体 可以在函数内部,只能在函数里面用
    struct Student {
        char name[10];
        unsigned int age;
        double high;
        char num[20];
    };

    struct  Student student;

    return 0;
}

image.png
//声明的形式
struct Student {
    char name[10];
    unsigned int age;
    double high;
    char num[20];
} stu1, stu2;

//没有名字的结构体,后面一定要接着声明变量
struct {
    char name[10];
    unsigned int age;
    double high;
    char num[20];
} stu4, stu5;


int main(void) {
    struct Student stu3;//struct一定要不要落下

    return 0;
}

定义 初始化

//初始化
struct Student {
    char name[10];
    unsigned int age;
    double high;
    char num[20];//学号
} stu1 = {"小晓", 18, 1.60, "20200409"}, stu2;

int main(void) {
    //顺序要对象,类型要对象
    struct Student stu3 = {"晓晓", 27, 1.65, "20200409"};

    return 0;
}

结构体取成员运算符

分两种: 实例变量struct Stu stu、指针变量struct Stu *p

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Student {
    char name[10];
    unsigned int age;
    double high;
    char num[20];//学号
} stu1 = {"小晓", 18, 1.60, "20200409"}, stu2;

int main(void) {
    //顺序要对象,类型要对象
    struct Student stu3 = {"晓晓", 27, 1.65, "20200409"};

    //1。实例变量取值
    //读
    // stu3.num和(&stu3)->num都行。因为指针是地址,p-> 其实就是地址->
    printf("%s,%d,%.2lf,%s\n", stu3.name, stu3.age, stu3.high, (&stu3)->num);//晓晓,27,1.65,20200409

    //2。指针变量取值
    //这个一定要初始化一定空间,可以直接指向对象,也可以malloc申请一块空间
    struct Student *p1 = &stu3;//指针指向对象的地址,
    //读
    printf("%s,%d,%.2lf,%s\n", p1->name, p1->age, p1->high, p1->num);//晓晓,27,1.65,20200409

    //3。也可以malloc申请一块空间
    struct Student *p = (struct Student *) malloc(sizeof(stu3));//申请一个空间
    p->age = 12;//赋值
    (*p).high = 1.8;
    strcpy(p->name,"大大");//p->name="asd"❌,因为数组定义好以后不能像初始化一样去赋值了
    strcpy((*p).num,"2020");//可以写成(*p).num
    //读
    printf("%s,%d,%.2lf,%s\n", p->name, p->age, p->high, p->num);//大大,12,1.80,2020

   // .和->优先级高于&和*

    return 0;
}

结构体成员的赋值

  1. 成员单个赋值
   p->age = 12;//赋值
   (*p).high = 1.8;
   strcpy(p->name,"大大");//p->name="asd"❌,因为数组定义好以后不能像初始化一样去赋值了
   strcpy((*p).num,"2020");//可以写成(*p).num
  1. 复合文字结构
    struct Student stu4;
    stu4 = (struct Student) {"晓晓", 27, 1.65, "20200409"}; //强制转换
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Student {
   char name[10];
   unsigned int age;
   double high;
   char num[20];//学号
} stu1 = {"小晓", 18, 1.60, "20200409"}, stu2;

int main(void) {
   struct Student stu3 = {"晓晓", 27, 1.65, "20200409"};

   struct Student stu4;
 //强制转换
   stu4 = (struct Student) {"晓晓", 27, 1.65, "20200409"};
   struct Student *p = &stu4;

   printf("%s,%d,%.2lf,%s\n", p->name, p->age, p->high, p->num);//晓晓,27,1.65,20200409
   printf("%s,%d,%.2lf,%s\n", stu4.name, stu4.age, stu4.high, stu4.num);//晓晓,27,1.65,20200409
   return 0;
}
  1. 部分元素初始化
    注意:初始化部分成员,其他的都默认为0、""


    image.png

指针成员与函数成员

指针成员

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Stu {
    int *p;
};

int main(void) {

    //1.null 2.栈区地址 3。堆区地址
    //1.
    struct Stu stu = {NULL};
    stu.p = malloc(8);

    //2.初始化结构体
    int a[5] = {1, 2, 3, 4, 5};
    struct Stu stu2 = {a};//a[0],&a
    //stu2.p是指针,.的优先级高于[]
    printf("%d,%d\n", stu2.p[0], stu2.p[4]);//1,5

    //3.malloc一个地址,然后指向数组
    struct Stu *p1 = (struct Stu *) malloc(sizeof(stu2));
    p1->p = a;// 或者 (*p1).p = a;
    printf("%d,%d\n", stu2.p[0], stu2.p[4]);//1,5

    //直接在结构体里malloc
    struct Stu stu1 = {(int *) malloc(20)};
    stu1.p[0] = 1;
    stu1.p[1] = 12;
    printf("%d,%d", stu2.p[0], stu2.p[1]);//1,2
    return 0;
}

函数成员
C的结构体不能调用函数,结构体中可以房函数的地址,这样就可以调用函数了,如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void fun(void) {
    printf("i am fun\n");
}

struct Stu {
    //函数的指针
    void (*p)();
};

int main(void) {
    //初始化 函数名就是函数地址
    struct Stu stu = {fun};
    //stu.p是函数地址,stu.p()调用函数
    stu.p(); //.和()级别相同,从左向右运算
    return 0;
}

结构体嵌套

1.嵌套多少层都可以
struct里面声明一个struct类型

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student {
    char name[10];
    int age;

};
struct Teacher {
    char name[10];
    int age;
    struct Student student;

};
int main(void) {
    //初始化
    struct Teacher teacher2 = {"张老师", 39, "晓晓", 27};
    //写不写花括号都可以
    struct Teacher teacher = {"张老师", 39, {"晓晓", 27}};

    struct Student student = {"大大", 27};
    struct Teacher teacher3 = {"李老师", 39, student};

    printf("%s,%d,%s,%d\n", teacher2.name, teacher2.age, teacher2.student.name, teacher2.student.age);//张老师,39,晓晓,27
    printf("%s,%d,%s,%d", teacher3.name, teacher3.age, teacher3.student.name, teacher3.student.age);//李老师,39,大大,27
    
    return 0;
}

2.struct里面写struct函数,不能直接初始化


image.png

结构体数组

一个数组,每个元素是结构体类型,他就叫结构体数组

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Teacher {
    char name[20];
    int age;
};

int main(void) {

    //加花括号可以部分不初始化
    struct Teacher teacher[3] = {{"张老师", 23},
                                 {"李老师", 29},
                                 {"王老师", 24}};

    //不加花括号也行
    struct Teacher teacher2[3] = {"张老师", 23,
                                  "李老师", 29,
                                  "王老师", 24};
    for (int i = 0; i < 3; ++i) {
        //结果:
        //张老师,23
        //李老师,29
        //王老师,24
        printf("%s,%d\n", teacher[i].name, teacher[i].age);
    }

    //    //加花括号可以部分不初始化
    struct Teacher teacher3[3] = {{"张老师"},
                                  {},
                                  {"王老师", 24}};

    //复合赋值
    teacher[0] = (struct Teacher) {"欧阳老师", 90};
    printf("%s,%d\n", teacher[0].name, teacher[0].age);//欧阳老师,90
    return 0;
}

结构体大小

内存对齐(字节对齐)

cpu处理数据
字节对齐:

假设数据挨着存储,char c,int a; 或者跨字节存储时,cpu要读两次,把两次读组成一个数据,效率就低了。
内存对齐是数据存储的规则,因为cpu读的规律是定的。假设我的数据按字节段存储char c,int a,分别存在各种的字节段,不垮字节段存储,那么每个数据cpu只需要读取一次就可以了。这种存储方式执行效率高,但是会浪费一点空间。
char c; short s;这两种如何存?
存在一个四字节的内存就够了,char存到第一个字节的时候,short存储在第三第四个字节,留出第二个。

结构体大小的计算规则

结构体大小是:结构体定义的变量所占的字节数。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Teacher {
    char c;
    int age;
    double d;
    short s;
};

int main(void) {
    
    struct Teacher teacher2;

    //解释看上面的图
    printf("%u,%u", sizeof(struct Teacher), sizeof(teacher2));//24,24
    return 0;
}

从上往下分配,如果上面int 和short换一下顺序,大小就改变了


image.png
struct Teacher {
    char c;
    short s;
    int age;
    double d;

};

int main(void) {

    struct Teacher teacher2;
    printf("%u,%u", sizeof(struct Teacher), sizeof(teacher2));//16,16
    return 0;
}

综上所述:结构体要是按照类型的自己数从小到达写的话,会节省空间。

手动设置字节对齐 : #pragma pack(4);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//手动设置内存对齐的字节数
#pragma pack(4) //设置的要小于等于结构体里面最大的那个自己数

struct Teacher {
    char c;
    int age;
    double d;
    short s;
};

int main(void) {

    struct Teacher teacher2;
    // 有#pragma pack(4):20  没有#pragma pack(4):24,24
    printf("%u,%u", sizeof(struct Teacher), sizeof(teacher2));
    
    //分析一下:
    //char c占在四字节的第一个字节
    //int age在四字节填满
    // double d占两个四字节
    // s在一个四字节的前两个内存中
    // 一共加起来是20个字节
    return 0;
}

注意:
1.结构体不能互相嵌套实例,可以嵌套指针
2.结构体不能包含自己的实例
以下错误❌


image.png

以下对🙆


image.png
上一篇 下一篇

猜你喜欢

热点阅读