结构体

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量

结构的声明

struct tag {
    mermber-list;
}variable-list

//例如描述一个学生
struct Stu{
    char name[20]; //名字
    int age; //年龄
    char Sex[5]; //性别
    char id[20]; //学号
}s4,s5,s6; //分号不能丢 全局变量

struct Stu s3; //全局变量

int main(){
    //创建结构体变量
    struct Stu s1;
    struct Stu s2;
}

特殊声明

//匿名结构体类型
struct {
    int a;
    char b;
    float c;
}x;

struct {
    int a;
    char b;
    float c;
}a[20],*p;

//上面两个结构在声明的时候省略了结构体标签(tag)
// p = &x;
//警告:编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。

结构体的自引用

//
struct Node{
    int data; //数据域
    struct Node *next; //指针域
};
int main(){
    return 0;
}

结构体变量的定义和初始化

struct Point {
    int x;
    int y;
}p1;       //声明类型的同时定义变量p1

struct Point p2; //定义结构体变量p2

//初始化:定义变量的同时赋初始值
struct Point p3 = {x,y};

struct Stu { //类型说明
    char name[15]; //名字
    int age;       //年龄
};

struct Stu s = {"zhangsan",20}; //初始化

struct Node{
    int data;
    scruct Point p;
    struct Node* next;
}n1= {10,{4,5},NULL} //结构体嵌套初始化

struct Node n2 = {20,{5,6},NULL}; //结构体嵌套初始化

结构体内存对齐

结构体_第1张图片

gcc没有默认对齐数

结构体_第2张图片

struct S1{
    char c1;
    int a;
    char c2;
};

struct S2{
    char c1;
    char c2;
    int a;
};

int main(){
    struct S1 s1 = {0};
    printf("%d\n",sizeof(s1));   //12   (4+4+1+n)%4=0 4+4+1+n=12
    struct S2 s2 = {0};
    printf("%d\n",sizeof(s2));   //8    

    return 0;
}

结构体传参

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销

如果传递的是一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降

结论:结构体传参的时候,要传结构体地址

#define _CRT_SECURE_NO-WANINGS 1

struct S{
    int a;
    char c;
    double d;
};

void Init(struct S *tmp){
    tmp -> a =100;
    tmp -> c = 'a';
    tmp -> d = 3.14;
}
//传值
void Printf1(struct S s){
    printf("%d %c %lf\n", s.a, s.c, s.d);
}
//传址
void Printf2(struct S *p){ // const struct S *p 如果加了const就不能改变 安全性高
    printf("%d %c %lf\n", p->a, p->c, p->d);
}

int main(){
    struct S s = {0}; //初始化
    Init(&s);
    Printf1(s);  //传结构体
    Printf2(&s); //建议传地址,节约空间
    return 0;
}

位段

节省空间

位段的声明和结构是类似的,有两个不同

  1. 位段的成员必须是int 、unsigned int 或 signed int
  2. 位段的成员后边有一个冒号和一个数字
struct S{
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;
};

int main(){
    struct S s;
    printf("%d\n",sizeof(s)); // 8
}

位段的内存分配

  1. 位段的成员可以是int、unsigned int、signed int或者是char(属于整形家族)类型
  2. 位段的空间是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的。
  3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段

枚举

列举

把可能的值一一列举

定义

enum Sex{
  MALE,
  FEMALE
};

enum Color{
    RED, //默认0
    GREEN, //1
    BLUE   //2
};

int main(){
    enum Sex  s = MALE;
    s = FEMALE;

    printf("%d %d %d \n",RED,GREEN,BLUE); //0 1 2
    return 0;
}
enum Color{
    RED =2, //设初始值
    GREEN , 
    BLUE =8  
};

int main(){
    printf("%d %d %d \n",RED,GREEN,BLUE); //2 3 8
    return 0;
}

枚举优点

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符比较枚举有类型检查,更为严谨
  3. 为了防止命名污染(封装)
  4. 便于调试
  5. 使用方便,一次可以定义多个变量

c语言的源代码 ---预处理---> 编译---->链接 ----> 可执行程序

枚举的使用

enum Color{
    RED =1, //设初始值
    GREEN = 4, 
    BLUE =8  
};

enum Color c = BLUE;  //只能拿枚举常量给枚举变量赋值,才不会出现类型的差异
c = 5 //错误

联合(联合体-共用体)

联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合体也叫共用体)

特点:

联合的成员是共用同一块内存空间的,这样一块联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)

面试题:判断当前计算机的大小端存储

union un{  //不能同时使用c和i
    char c; //1
    int i;  //4 
};
//5个字节

int main(){
    union un u;
    printf("%d\n",sizeof(u));//4
    return 0;
}

联合大小的计算

  • 联合的大小至少是最大成员的大小
  • 当最大成员大小不是对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
union un{  
    char arr[5];
    char c; //1
    int i;  //4
};
int main(){
    union un u;
    printf("%d\n",sizeof(u));//8
    return 0;
}

你可能感兴趣的:(C++,c++,c语言)