0
点赞
收藏
分享

微信扫一扫

【机器学习】调配师:咖啡的完美预测

凶猛的小白兔 2024-01-22 阅读 14

        本篇博客详细介绍C语言最后的三种自定义类型,它们分别有着各自的特点和应用场景,重点在于理解这三种自定义类型的声明方式和使用,以及各自的特点,最后重点掌握该章节常考的考点,如:结构体内存对齐问题,使用联合判断字节序的存储问题。学完本篇博客达到理解会运用!

一、结构体(struct)

1.1 结构体类型的声明和结构体的嵌套以及结构体指针(是指针)

//.c文件中(C语言语法)普通的声明结构体的方式和定义结构体变量
struct Address
{
    char name[20];
    char area[20];
};                  //分号不能少
 
struct Student
{
    char * name1;         //字符串指针
    const char * name2;   //字符串指针,用const修饰,只可通过指针解引用访问,不可进行修改
    char name3[20];       //字符数组
    int id;
    float  score;
    Address address;     //结构体嵌套
};         
   
int main()
{
    //定义结构体变量
    struct Student s={"张三","李四","王五",111,98.5,{"王麻子","陕西"}};
    //定义结构体指针
    struct Student * ps=&s;
 


//.cpp文件中(C++语法)语普通的声明结构体的方式和定义结构体变量
struct Address
{
    char name[20];
    char area[20];
};                  //分号不能少
 
struct Student
{
    char * name1;         //字符串指针
    const char * name2;   //字符串指针,用const修饰,只可通过指针解引用访问,不可进行修改
    char name3[20];       //字符数组
    int id;
    float  score;
    Address address;     //结构体嵌套
};         
   
int main()
{
      //定义结构体变量
     Student s={"张三","李四","王五",111,98.5,{"王麻子","陕西"}};
     //定义结构体指针
     Student * ps=&s;

     return 0;
}
 
//结构体声明结合typedef使用
 
typedef struct Address
{
    char name[20];
    char area[20];
}Address;                  //分号不能少
 
 
typedef struct Student
{
    char * name1;         //字符串指针
    const char * name2;   //字符串指针,用const修饰,只可通过指针解引用访问,不可进行修改
    char name3[20];       //字符数组
    int id;
    float  score;
    Address address;     //结构体嵌套
}Student,*Ps;         
   
//利用typedef对结构体和结构体指针进行重命名
//相当于:typedef struct Student  Student
//相当于:typedef struct Student*  Ps
 

int main()
{
     //定义结构体变量
     Student s={"张三","李四","王五",111,98.5,{"王麻子","陕西"}};
     //定义结构体指针
     Ps=&s;

1.2 结构体变量的定义及初始化

    Student s={"张三","李四","王五",111,98.5,{"王麻子","陕西"}};

       结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。 

1.3 结构体成员的三种访问方式

#include <stdio.h>
typedef struct Address
{
    char name[20];
    char area[20];
}Address,* Pa;
 
typedef struct Student
{
 
    const char* name1;   //字符串指针,用const修饰,只可通过指针解引用访问,不可进行修改
    int id;
    float  score;
    Address address;     //结构体嵌套
}Student, * Ps;
 
int main()
{
 
    Student s = { "张三",22203,99.5,{"王恒","西安市"} };
    Ps p = &s;
    //使用代码实现访问s中的成员address中的area成员(嵌套访问)
    //第一种访问方式:通过结构体变量访问结构体成员:结构体变量.结构体成员名
    printf("%s ""%d ""%f ""%s ""%s \n",s.name1,s.id,s.score,s.address.name,s.address.area);
 
   //第二种访问方式:通过结构体指针变量先解引用找到该结构体变量再 . 访问
    printf("%s ""%d ""%f ""%s ""%s \n", (*p).name1, (*p).id, (*p).score, (*p).address.name, (*p).address.area);
 
    //第三种访问方式:为了简化第二种引入指向符: ->访问
    printf("%s ""%d ""%f ""%s ""%s ", p->name1, p->id, p->score, p->address.name, p->address.area);
 
        return 0;
}

1.4 结构体数组(是数组)

#include <stdio.h>

// 结构体声明
typedef struct Person 
{
    char name[50];
    int age;
    float height;
}Person;

int main() 
{
    // 创建结构体数组并初始化
     Person people[3] = {{"Alice", 30, 160.5},{"Bob", 25, 175.0},{"Charlie", 35, 180.2}};
    // 访问结构体数组元素
    for (int i = 0; i < 3; ++i) 
   {
        printf("Person %d\n", i + 1);
        printf("Name: %s\n", people[i].name);
        printf("Age: %d\n", people[i].age);
        printf("Height: %.2f\n", people[i].height);
        printf("\n");
    }
    return 0;
}

1.5 结构体的内存对齐及结构体占用内存的计算(重点)

1.5.1 为什么存在内存对齐?

1.5.2 结构体大小的计算(重点)

//练习1
#include<stdio.h>
struct S1
{
   char c1;
   int i;
   char c2;
};

int main()
{
     printf("%d\n", sizeof(struct S1));
     return 0;
}

//练习2
#include<stdio.h>
struct S2
{
   char c1;
   char c2;
   int i;
};

int main()
{
     printf("%d\n", sizeof(struct S2));
     return 0;
}

//练习3
#include<stdio.h>
struct S3
{
   double d;
   char c;
   int i;
};
int main()
{
     printf("%d\n", sizeof(struct S3));
     return 0;
}

//练习4-结构体嵌套问题
#include<stdio.h>

struct S3
{
    double d;
    char c;
    int i;
};
struct S4
{
    char c1;
    struct S3 s3;
    double d;
};


int main()
{
    printf("%d\n", sizeof(struct S4));
    return 0;
}


 

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
   char c1;
   int i;
   char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

#pragma pack(1)//设置默认对齐数为1
struct S2
{
   char c1;
   int i;
   char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

1.6 结构体传参

1.7 位段(了解)

1.7.1 什么是位段

struct bs
{
    unsigned m;
    unsigned n: 4;
    unsigned char ch: 6;
};

1.7.2 位段的内存分配

1.7.3 位段的跨平台问题

总结:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

二、枚举(enum)

2.1 枚举类型的定义

        在实际编程中,有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便在后续代码中使用,比如一个星期只有七天,一年只有十二个月,一个班每周有六门课程等。#define命令虽然能解决问题,但也带来了不小的副作用,导致宏名过多,代码松散,看起来总有点不舒服。C语言提供了一种枚举(Enum)类型,能够列出所有可能的取值,并给它们取一个名字。

#include <stdio.h>

#define Mon 1
#define Tues 2
#define Wed 3
#define Thurs 4
#define Fri 5
#define Sat 6
#define Sun 7

int main(){
    int day;
    scanf("%d", &day);
    switch(day){
        case Mon: puts("Monday"); break;
        case Tues: puts("Tuesday"); break;
        case Wed: puts("Wednesday"); break;
        case Thurs: puts("Thursday"); break;
        case Fri: puts("Friday"); break;
        case Sat: puts("Saturday"); break;
        case Sun: puts("Sunday"); break;
        default: puts("Error!");
    }
    return 0;
}
例如,列出一个星期有几天:
enum week{ Mon, Tues, Wed, Thurs, Fri, Sat, Sun };
可以看到,我们仅仅给出了名字,却没有给出名字对应的值,这是因为枚举值默认从 0 开始,往后逐个加 1(递增);也就是说,week 中的 Mon、Tues ...... Sun 对应的值分别为 0、1 ...... 6。

我们也可以给每个名字都指定一个值:
enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 };

更为简单的方法是只给第一个名字指定值:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
这样枚举值就从 1 开始递增,跟上面的写法是等效的。

enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a, b, c;
enum week a = Mon, b = Wed, c = Sat;
判断用户输入的是星期几。
#include <stdio.h>
int main(){
    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;
    scanf("%d", &day);
    switch(day){
        case Mon: puts("Monday"); break;
        case Tues: puts("Tuesday"); break;
        case Wed: puts("Wednesday"); break;
        case Thurs: puts("Thursday"); break;
        case Fri: puts("Friday"); break;
        case Sat: puts("Saturday"); break;
        case Sun: puts("Sunday"); break;
        default: puts("Error!");
    }
    return 0;
}

2.2 枚举类型的使用

enum Color//颜色
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;               //ok??错误!!!

2.3 枚举类型的特点

三、联合(共用体)(union)

       在C语言中,变量的定义是分配存储空间的过程。一般的,每个变量都具有其独有的 存储空间,那么可不可以在同一个内存空间中存储不同的数据类型(不是同时存储)呢? 答案是可以的,使用联合体就可以达到这样的目的。联合体也叫共用体,在C语言中 定义联合体的关键字是union。 

3.1 联合类型的定义

union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;

3.2 联合类型的特点及利用联合判断判断字节序的存储方式

3.2.1 特点

#include<stdio.h>
union Un
{
    int i;
    char c;
};
union Un un;

int main()
{
    // 下面输出的结果是一样的吗?
    printf("%d\n", &(un.i));
    printf("%d\n", &(un.c));
在联合体中,所有成员共享同一块内存,因此这两行输出的地址应该是相同的。
    //下面输出的结果是什么?
    un.i = 0x11223344;
    un.c = 0x55;
    printf("%x\n", un.i);;
//由于联合体的特性,此时整型成员i的值将被覆盖为字符型成员c的值,因此输出的结果将是55。
    return 0;
}

3.2.2 利用联合判断判断字节序的存储方式

#include <stdio.h>
union union_test 
{
	int s; 
	char t;
}test;

int main()
 {
	printf("联合体 union_test 所占的字节数:%d\n", sizeof(union union_test));
	test.s = 0x12345678;
	if (0x78 == test.t) 
	{
		printf("小端模式\n");
	}
	else 
	{
		printf("大端模式\n");
	}
	return 0;
}

       以上便是自定义类型全部内容,认真理解消化,一定会有极大的收获,可以留下你们点赞、关注、评论,您的支持是对我极大的鼓励,下期再见!

举报

相关推荐

0 条评论