自定义类型【C语言】

目录

C语言的类型

自定义类型---结构体

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

2.结构的声明:

3.结构体传参

结构体实现位段

自定义类型---枚举

自定义类型---联合(共同体)


C语言的类型

字符型:char

整形:short / int / long / longlong ---C99

字符型:float / double

Bool----C99

自定义类型---结构体

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

2.结构的声明:

//类型声明
stuct book
{
    char name[20];     //作者名字
    char bookname[20]; //书名
}


结构体内存对齐

offsetof(宏):用来计算结构体成员相对于起始位置的偏移量

结构体内存对齐规则:

1.第一个成员与结构体变量偏移量为0的地址处。

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数=编译器默认的一个对齐数与该成员的较小值。

(VS中默认的值为8)

(Linux环境默认不设对齐数----对齐数是结构体成员自身大小)

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的这整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体对到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

 char:对齐数为1,int:对齐数为4,所以最大对齐数为4

(共占12个)

为什么需要内存对齐:因为结构体的内存对齐是拿空间来换取时间的做法

(如上,有许多空间都浪费,怎么样能让空间不浪费呢?

可以让内存空间小的类型尽量放在一起)

3.结构体传参

struct stu{
    char name[20];
    char sex[5];
    int age;
}
void Print_1(struct stu s)
{
    printf("%d\n",s.age);
}
void Print(struct stu* s)
{
printf("%d\n",s->age);
}

int main()
{
    struct stu_stu={"xiaoming","boy",18};
    //传结构体
    Print_1(_stu);
    //传地址
    Print(&_stu);
    return 0;
}

(结构体传参时不传结构体,要传结构体的地址,因为结构体指针可能包含很大数组(结构体过大,参数在压栈的时候系统开销过大,导致性能下降)

结构体实现位段

位段内存的分配:

1.位段成员可以是int,unsigned int,signed int;

2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的

3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用的位段

如:

struct s
{
    char a:3;
    char b:4;
    char c:5;
    char d:4;
};
int main()
{
    struct s s1={0};
    printf("%d,sizeof(s1));
    return 0;
}

给a分配一个字节,a占三个bit,还剩五个bit,给b用bit,b用四个bit,还剩一个bit,给c不够,舍弃哪一个,再给c分配一个字节空间,还剩三个bit,给d不够,舍弃那三个bit,给d分配一个字节

所以一共占三个字节

(位段跨平台问题)

1.int位段被当成有符号数还是无符号数是不确定

2.位段中最大位的数目不能确定(16位机器最大16,32/64最大32)

3.位段中的成员在内存中从左往右分配还是从右往左分配标准尚未定义

4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个文段剩余的位时,是舍弃还是利用不能确定。

自定义类型---枚举

enum Sex
{
    MALE,
    FEMALE,
    SECRET
}

如果在定义中没给枚举成员赋值,默认从0开始

枚举和宏都可以定义常量,枚举的优点:

1.增加代码的可读性和可维护性

2.和#define定义的标识符比较,枚举有类型检查,更加严谨

3.防止了命名污染(封装)

4.便于调试,(#define在编译环节进行处理)

5.使用方便,一次可以定义多个常量

自定义类型---联合(共同体)

联合类型的定义:联合是一种特殊的自定义类型,这种类型定义的变量耶包含一系列的成员,特征是这些成员共用同一块空间

union Um
{
    char c;
    int i;
};
int main()
{
    union Um un;
    printf("%d\n",sizeof(un));
    system("pause");
    return 0;
}

联合的特点:

1.联合的成员共用同一块内存空间,因此一个联合变量的大小,至少是最大成员的大小;联合体的任何一个成员都是联合体的第一个成员

2.根据联合体的特定可以用来判断当前计算机的大小端存储

#include<stdio.h>
union Un{
    int i;
    char c;
};
int main()
{
    union Un un;
    printf("%d\n",&(un.i));
    printf("%d\n",&(un.c));

    un.i=0x11223344;
    un.c=0x55;
    printf("%x\n",un.i);
    system("pause");
    return 0;
}

联合大小的计算

1.联合体大大小至少是最大成员的大小

2.如果最大成员大小不是对齐数的整倍数的时候,就要对齐到最大的整数倍;联合体最后开辟的空间必须能够整除自身的最大对齐数

自定义函数在C语言中是一种强大的编程工具,它允许程序员组织代码并将其封装在一个特定的任务中。以下是自定义函数的一些关键要素: 1. **函数声明**: - 使用`void`, `int`, `float`, `char`等数据类型指定返回值类型,如果没有返回值则用`void`表示。 - 函数名、输入参数(如果有)以及它们的数据类型放在圆括号内,如`void myFunction(int arg1, char arg2)`。 2. **函数定义**: - 在函数体中编写实际的操作,通常包含一系列指令。 - 可以在同一文件中定义(内部函数),也可以在其他位置定义(外部函数,需要通过头文件包含)。 - 使用`{}`包围函数体,并按照缩进来组织代码块。 3. **参数传递**: - C语言支持值传递(Pass by Value),默认情况下实参复制给形参,修改形参不会影响实参。 - 如果想要改变实参内容,可以使用指针或引用(Pass by Reference),但这不是C语言的标准特性,而是编译器提供的额外功能。 4. **返回值**: - 如果函数有返回值,要在函数体结束时使用`return`语句返回结果。 - `return`语句可以带有一个表达式,其结果会被作为函数的返回值。 5. **递归**: - 有时候会用到函数调用自身的情况,这就构成了递归。递归函数需满足基本情况(终止条件)和一般情况(调用自身处理更小的问题)。 6. **作用域**: - 根据函数定义的位置,函数拥有局部(只在函数内部可见)或全局(在整个程序中可用)的作用域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值