结构体 、位段、枚举、联合自定义类型

5 篇文章 0 订阅

自定义类型:

 

一、结构体类型

1.结构体声明

       也叫结构,是由一系列具有相同类型或不同类型的数据构成的数据集合。

//描述一个学生

//直接声明
struct stu{
    char name[20];
    int age;
    char sex[20];
    char id[20];
};

//匿名结构体类型
struct {
    char name[20];
    int age;
    char sex[20];
    char id[20];
} stu;

struct  {
    char name[20];
    int age;
    char sex[20];
    char id[20];
} *p;

  注:第一种为结构体直接声明的形式,后面两种为不完全声明,但后面这两种默认为不相同的两种类型(两个独立的结构体)

stu = &p  是错误的表达。

2.结构体自引用

     结构体中包含一个,本身结构体类型的变量。

struct Node{
    int value;
    struct Node* next;  //结构体类型的指针
};

   常见的使用实例为链表创建:

//单向无头不循环链表
typedef struct Node{
    int value;
    struct Node* next;
} Node;

//双向有头循环链表
typedef struct Node{
    int value;
    struct Node* next;
    struct Node* prev;   //指向的方向不同
} Node;

3.结构体变量定义和初始化

   可同时进行,也可先定义后初始化。

   如下例子声明、定义、初始化

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;
    struct Point p;
    struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化

4.结构体变量在函数中传参

   两种形式,穿变量,传指针

struct Stu
{
	char name[10];
	int age;
};
void person1(struct Stu stu)
{
	strcpy(stu.name , "pipifei");//字符串赋值
	stu.age = 18;                //结构体成员调用
	printf("%s    %d\n", stu.name, stu.age);
}
void person2(struct Stu* P)
{
	strcpy(P->name , "wangtengfei");
	P->age = 25;                //结构体成员调用
	printf("%s    %d\n", P->name, P->age);
}
int main()
{
	struct Stu stu;        //结构体名定义
	struct Stu* Per = &stu;//结构体调用
	person1(stu);          //结构体传参1
	person2(Per);          //结构体传参2
}

5.结构体内存对齐

      是计算结构体大小时的一个规则。

     对齐规则:1. 第一个成员在与结构体变量偏移量为0的地址处。
                       2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处

                            对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8
                             Linux中的默认值为4

                        3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
                        4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是
                            所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

   例1:

#include <stdio.h>

struct Stu{
	char name;
	int age;
	char sex;
	int score;
}S;

int main()
{
	printf("结构体的大小为:%d\n", sizeof(S));

	printf("%p\n", &S);
	printf("%p\n", &S.name); 
	printf("%p\n", &S.age);
	printf("%p\n", &S.sex);
	printf("%p\n", &S.score);
	return 0;
}

结果:
结构体的大小为:16
00157560
00157560              第一个成员的地址和结构体的地址相同
00157564
00157568              min(编译器默认8,当前字段的sizeof)  =  4
0015756C              结构体大小 = 4 * 4
请按任意键继续. . .

例2:

#include <stdio.h>

struct Stu{
	int name;    
	char age;    
	char sex;
	int score;
}S;

int main()
{
	printf("结构体的大小为:%d\n", sizeof(S));

	printf("%p\n", &S);
	printf("%p\n", &S.name); 
	printf("%p\n", &S.age);
	printf("%p\n", &S.sex);
	printf("%p\n", &S.score);
	return 0;
}

结构体的大小为:12
01247560
01247560
01247564
01247565             结构体大小 = 4 * 3
01247568             
请按任意键继续. . .

例3:

#include <stdio.h>

struct Stu{
	char name;
	char age;
	char sex;
	int score;
}S;

int main()
{
	printf("结构体的大小为:%d\n", sizeof(S));

	printf("%p\n", &S);
	printf("%p\n", &S.name); 
	printf("%p\n", &S.age);
	printf("%p\n", &S.sex);
	printf("%p\n", &S.score);
	return 0;
}

结构体的大小为:8
00EE7560
00EE7560
00EE7561
00EE7562     结构体大小 = 4 * 2
00EE7564      
请按任意键继续. . .

例4:

#include <stdio.h>

struct Stu{
	char name;
	char age;
	char sex;
	char score;
}S;

int main()
{
	printf("结构体的大小为:%d\n", sizeof(S));

	printf("%p\n", &S);
	printf("%p\n", &S.name); 
	printf("%p\n", &S.age);
	printf("%p\n", &S.sex);
	printf("%p\n", &S.score);
	return 0;
}

结构体的大小为:4
0138755C
0138755C
0138755D     对齐数 = 1
0138755E      
0138755F
请按任意键继续. . .

6.修改默认对齐数

#pragma pack(8)     //设置默认对齐数为8

例:

#include <stdio.h>

#pragma pack(1)//设置默认对齐数为1

struct Stu{
	char name;
	int age;
	char sex;
	int score;
}S;

#pragma pack()//取消设置的默认对齐数,还原为默认

int main()
{
	printf("结构体的大小为:%d\n", sizeof(S));

	printf("%p\n", &S);
	printf("%p\n", &S.name); 
	printf("%p\n", &S.age);
	printf("%p\n", &S.sex);
	printf("%p\n", &S.score);
	return 0;
}

结构体的大小为:10            修改默认对齐数为1
00887560
00887560
00887561
00887565
00887566
请按任意键继续. . .

二、位段

1.什么是位段

位段的声明和结构是类似的,有两个不同:
          1.位段的成员必须是 int、unsigned int 或signed int 。
          2.位段的成员名后边有一个冒号和一个数字

struct A     //A就是个位段类型
{
    int _a:2;
    int _b:5;
    int _c:10;
    int _d:30;   //47个bit位  按int类型 为8个字节
};

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

2.位段的内存分配


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

3.位段的跨平台问题


       1. int 位段被当成有符号数还是无符号数是不确定的。
       2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问
           题。
       3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
       4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的
          位还是利用,这是不确定的

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

 

三、枚举

        枚举顾名思义就是一一列举。

1.枚举类型的定义

enum Day//星期
{
    Mon,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};
enum Sex//性别
{
    MALE,
    FEMALE,
    SECRET
};

以上定义的 enum Day , enum Sex都是枚举类型, {}中的内容是枚举类型的可能取值,也叫 枚举常量 。
    这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值

2.枚举的优点

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

3.枚举的使用

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

四、联合(共同体)

1.联合类型的定义

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

//联合类型的声明
union Un
{
char c;
int i;
};
//联合变量的定义
union Un un;
//计算连个变量的大小
printf("%d\n", sizeof(un));

2.联合的特点

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

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

1、法1

大端模式(Big_endian)   -- 字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。

小端模式(Little_endian)-- 字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。

根据这个特性,假设我们初始化了一个int变量i为0x12345678,其地址为0x100,根据定义在小端模式下

0x100一个字节内的值为0x78,类推0x101=>0x56,0x102=>0x34,0x103=0x12,

int checkSystem(void)
{
	int i = 0x12345678;
	char *c = &i;
	return ((c[0] == 0x78) && (c[1] == 0x56) && (c[2] == 0x34) && (c[3] == 0x12));
}

int main()
{
	int ret = checkSystem();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;

}


2、法2

在union中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同

的起始地址。即上述的union虽然定义了两个成员,但其实这个union只占用了4个字节(32位机器中),往a成员

赋值,然后读取b就相读取a成员的低位第一个字节的值。如果机器使用大端模式,则u.a=1那a的最高字节值为1;

如果机器使用小段模式,则u.a=1则a的最低位字节为1。上述可知b和a有相同的起始位,所以读取b如果等于1,

则为小端模式,b为0则为大端模式
 

#include <stdio.h>
#include <stdlib.h>
int check_sys()
{
	union
	{
	  int i;
	  char c;
	}un;
	un.i = 1;
	return un.c;
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;

}

 

3.联合的大小

       联合的大小至少是最大成员的大小。
       当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};

int main(){
    //下面输出的结果是什么?
    printf("%d\n", sizeof(union Un1));     //8
    printf("%d\n", sizeof(union Un2));     //16
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中,结构体是一种自定义数据类型,可以将不同类型的变量组合在一起,形成一个新的数据类型结构体定义的基本形式如下: ```c struct 结构体名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其中,结构体名是用户自定义的名称,成员名是结构体中每个成员的名称,数据类型可以是任意C语言的数据类型,包括基本数据类型自定义数据类型结构体变量的定义方式如下: ```c struct 结构体名 变量名; ``` 读取结构体中的成员变量可以通过“.”运算符来实现,例如: ```c #include <stdio.h> struct Person { char name[20]; int age; }; int main() { struct Person p; printf("请输入姓名:"); scanf("%s", p.name); printf("请输入年龄:"); scanf("%d", &p.age); printf("姓名:%s,年龄:%d\n", p.name, p.age); return 0; } ``` 枚举是一种特殊的数据类型,用于定义一组常量。枚举的定义方式如下: ```c enum 枚举名 { 常量名1, 常量名2, // ... }; ``` 其中,枚举名是用户自定义的名称,常量名是枚举中每个常量的名称。枚举常量的值默认是从0开始自动递增的,也可以手动指定值。例如: ```c #include <stdio.h> enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; int main() { enum Weekday today = Tuesday; printf("今天是星期%d\n", today + 1); return 0; } ``` 联合是一种特殊的数据类型,它的成员变量共享同一块内存空间。联合的定义方式如下: ```c union 联合名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其中,联合名是用户自定义的名称,成员名是联合中每个成员的名称,数据类型可以是任意C语言的数据类型,但所有成员的大小不能超过联合的大小。例如: ```c #include <stdio.h> union Number { int i; float f; }; int main() { union Number n; n.i = 123; printf("int: %d, float: %.2f\n", n.i, n.f); n.f = 3.14; printf("int: %d, float: %.2f\n", n.i, n.f); return 0; } ``` 以上就是C语言自定义数据类型中的结构体枚举联合的基本用法和注意事项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值