C语言基础(十八)

1、共用体(Union)是一种特殊的数据类型,也被称为联合体,它允许在相同的内存位置存储不同的数据类型,每次只能存储其中一种类型的值。共用体是一种数据结构,多个不同类型的变量能够共享同一段内存空间。在C语言中,共用体通过关键字union定义。

主要用途
节省内存:当程序中需要存储多种类型的数据,但同一时间只使用其中一种类型时,可以使用共用体来节省内存空间。因为共用体的总长度等于其成员中最长数据类型的长度,而不是所有成员长度之和。
数据转换:共用体可以用于不同类型数据之间的快速转换,例如,可以将一个整数存储在一个共用体中,然后将其解释为浮点数或字符数组等。
特定场景下的高效操作:在需要处理多种数据类型但每次只处理一种的场景下,如硬件编程、网络通信协议解析等,共用体可以提供高效的数据处理方式。

特别之处
共享内存:共用体的所有成员共享同一段内存空间,在同一时刻,共用体只能存储其成员中的一种类型的数据。
长度特性:共用体的长度等于其成员中最长数据类型的长度。
赋值特性:对共用体中的任一成员赋值都会覆盖该内存位置上的旧值,因此共用体变量中起作用的成员是最后一次被赋值的成员。

定义与声明
共用体的定义和声明方式如下:

union 共用体名 {  
    类型1 成员名1;  
    类型2 成员名2;  
    ...  
    类型N 成员名N;  
};  
  
// 声明共用体变量  
union 共用体名 变量名;
 

测试代码:

#include "date.h"
#include <stdio.h>  
// 定义共用体  
union MyUnion {  
    char c;  
    short s;  
    int i;  
    long long ll;  
};  
  
int main() {
	
	int time = getTime();
	
    union MyUnion myUnion;  
  
    // 初始化共用体的 long long 成员  
    myUnion.ll = 0x123456789ABCDEF0LL;  
  
    // 打印 long long 成员的值,验证初始化  
    printf("long long ll: %lld (0x%llx)\n", myUnion.ll, myUnion.ll);  

    // 检查其他成员的值,它们共享同一段内存。  
    // 这些打印的值将取决于我们如何解释这段内存(即,作为 char、short、int 还是 long long)  
  
    // 打印 char 成员的值(只取最低字节)。  
    printf("char c: %c (0x%x)\n", myUnion.c, (unsigned char)myUnion.c);  
  
    // 打印 short 成员的值(取最低两个字节,注意字节序)。  
    // 假设系统是小端字节序  
    printf("short s: %d (0x%x)\n", myUnion.s, (unsigned short)myUnion.s);  
  
    // 打印 int 成员的值(取最低四个字节,注意字节序)。  
    // 假设系统是小端字节序 。 
    printf("int i: %d (0x%x)\n", myUnion.i, (unsigned int)myUnion.i);  
  
    // 内存布局,打印出每个成员的地址。  
    // 这些地址将是相同的(对于某些编译器和平台,偏移量将是内存对齐的倍数)。  
    printf("Addresses:\n");  
    printf("&myUnion.ll: %p\n", &myUnion.ll);  
    printf("&myUnion.c: %p\n", &myUnion.c);  
    printf("&myUnion.s: %p\n", &myUnion.s);  
    printf("&myUnion.i: %p\n", &myUnion.i);  
    // 由于是共用体的成员,所以它们的地址在逻辑上是相同的。  
    // 编译器会根据类型给出不同的指针类型(比如 char*、short*、int*、long long*)。  
    return 0;  
}

运行结果如下:

...........................................................................................................................................................

2、枚举(Enumeration)是用户定义的类型,允许程序员为整数指定一个更容易理解的名字。枚举类型是一组命名的整型常量,在逻辑上相关,通常用于表示状态、选项或其他类似的集合。

枚举类型的定义使用enum关键字,后跟枚举类型的名称和用花括号括起来的一组枚举常量。每个枚举常量都是一个整数,默认情况下,从0开始,每个后续常量递增1。也可以显式地指定某个枚举常量的值。

测试代码1:

#include "date.h"
#include <stdio.h>  
// 定义一个枚举。  
// 枚举成员的默认值是从0开始的整数序列,也可以在枚举定义中显式指定它们。 
enum days {  
    Sunday,  
    Monday,  
    Tuesday,  
    Wednesday,  
    Thursday,  
    Friday,  
    Saturday  
};  
  
int main() {  

    int time = getTime();
    enum days today;  
      
    // 使用枚举成员直接赋值。  
    today = Tuesday;  
    printf("Today is day %d of the week.\n", today);  
      
    // 直接将int赋给枚举变量,建议使用显式转换让代码更清晰。 
    int dayNumber = 3; // 3代表Wednesday  
    today = (enum days)dayNumber; // 显式转换  
    printf("This day with value %d is %d.\n", dayNumber, today);  
      
    // 直接使用枚举成员。  
    printf("Thursday is %d.\n", Thursday);  
      
    return 0;  
}

运行结果如下:

测试代码2:

#include "date.h"
#include <stdio.h>  
// 定义一个枚举 
enum days {  
    Sunday = 1,  // 显式指定Sunday的值为1  
    Monday = 2,  
    Tuesday = 3,  
    Wednesday = 4,  
    Thursday = 5,  
    Friday = 6,  
    Saturday = 7  
};  
  
int main() {  
    int time = getTime(); 
    enum days today = Wednesday; // today的值为4  
  
    // 打印today的值  
    printf("Today is day %d of the week.\n", today);  
  
    // 使用显式指定的值  
    enum days specialDay = (enum days)6; 
    printf("Special day is %d.\n", specialDay);  
  
    // 使用枚举成员直接比较  
    if (specialDay == Wednesday) {  
        printf("Yes, it's Wednesday!\n");  
    }  else{
    	printf("It's not Wednesday.\n");  
    }
  
    return 0;  
}

运行结果如下:

测试代码3:

#include "date.h" 
#include <stdio.h>  
#include <string.h>  
  
// 定义枚举类型 JobType,包含STUDENT和TEACHER两个值。  
typedef enum { STUDENT, TEACHER } JobType;  
  
// 定义结构体 Person,包含学号、姓名、工作类型、工作类别联合体,以及指向下一个Person结构的指针。  
struct Person {  
    int num;  
    char name[20];  
    JobType job;  
    union {  
        int clas;  
        char position[11]; // +1 for null terminator 。 
    } category; // union 是结构体 Person 的一个成员 。 
    struct Person* next;  
};  
// 定义初始化学生信息的函数 initStudent,设置学号、姓名、工作类型和班级信息,以及将下一个指针置为空。 
void initStudent(struct Person* person, int num, const char* name, int clas) {  
    person->num = num;  
    strcpy(person->name, name);  
    person->job = STUDENT;  
    person->category.clas = clas;  
    person->next = NULL;  
}  
// 定义初始化老师信息的函数 initTeacher,设置工号、姓名、工作类型和职位信息,以及将下一个指针置为空。 
void initTeacher(struct Person* person, int num, const char* name, const char* position) {  
    person->num = num;  
    strcpy(person->name, name);  
    person->job = TEACHER;  
    strcpy(person->category.position, position);  
    person->category.position[10] = '\0'; 
    person->next = NULL;  
}  
  
int main() {  
    int time = getTime();
    // 创建名为student和teacher的结构体实例。 
    struct Person student, teacher;
	// 调用initStudent和initTeacher函数初始化。  
    initStudent(&student, 1, "Alice", 3);  
    initTeacher(&teacher, 2, "Bob", "Professor");  
  
     // 使用条件语句检查学生和老师的工作类型,并打印相应的信息。 
    if (student.job == STUDENT) {  
        printf("Student #%d, Name: %s, Class: %d\n", student.num, student.name, student.category.clas);  
    }  
  
    if (teacher.job == TEACHER) {  
        printf("Teacher #%d, Name: %s, Position: %s\n", teacher.num, teacher.name, teacher.category.position);  
    }  
  
    return 0;  
}

运行结果如下:

测试代码4:

#include "date.h"
#include <stdio.h>  
#include <stdlib.h>  
#include <time.h>  
// 定义一个枚举类型Suit,表示扑克牌的花色 
typedef enum { CLUBS, DIAMONDS, HEARTS, SPADES } Suit;  
// 定义一个结构体Card,表示一张扑克牌,包括rank(点数)和suit(花色)两个成员变量。
typedef struct {  
    int rank;  
    Suit suit;  
} Card;  
// shuffle函数,对一副牌进行洗牌操作,通过随机交换牌的位置洗牌。 
void shuffle(Card deck[], int n) {  
    srand(time(0));  
    for (int i = 0; i < n; i++) {  
        int j = rand() % n;  
        Card temp = deck[i];  
        deck[i] = deck[j];  
        deck[j] = temp;  
    }  
}  
// printCard函数,打印一张扑克牌的点数和花色。 
void printCard(Card card) {  
    switch (card.rank) {  
        case 1:  
            printf("Ace");  
            break;  
        case 11:  
            printf("Jack");  
            break;  
        case 12:  
            printf("Queen");  
            break;  
        case 13:  
            printf("King");  
            break;  
        default:  
            printf("%d", card.rank);  
    }  
  
    switch (card.suit) {  
        case CLUBS:  
            printf(" of Clubs\n");  
            break;  
        case DIAMONDS:  
            printf(" of Diamonds\n");  
            break;  
        case HEARTS:  
            printf(" of Hearts\n");  
            break;  
        case SPADES:  
            printf(" of Spades\n");  
            break;  
    }  
}  
  
int main() {  
    int time = getTime();
    // 创建一个包含52张扑克牌的数组deck
    const int NUM_CARDS = 52;  
    Card deck[NUM_CARDS];  
    // for循环初始化每一张牌的点数和花色。
    for (int i = 0; i < NUM_CARDS; i++) {  
        deck[i].rank = (i % 13) + 1;  
        deck[i].suit = static_cast<Suit>(i / 13);  //显式类型转换。 
        // 打印洗牌前的点数和花色。 
		printCard(deck[i]); 
    }  
    printf("\n");
    // 调用shuffle函数进行洗牌
    shuffle(deck, NUM_CARDS);  
    // 循环打印洗牌后每张牌的点数和花色。 
    for (int i = 0; i < NUM_CARDS; i++) {  
        printf("Card %d: ", i + 1);  
        printCard(deck[i]);  
    }  
  
    return 0;  
}

运行结果如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值