首页 > 其他分享 >C语言(四)

C语言(四)

时间:2023-07-12 20:22:04浏览次数:44  
标签:typedef struct int 成员 C语言 char 变量

目录

9.结构体

9.1引入

假如要保存一些人的信息,需要

  • 姓名 -- char name[100];
  • 性别 -- char sex;
  • 民族 -- char nation
  • 身份证号 -- char id[20];
  • 身份证有效期 -- ...
  • 年龄 -- int age;
  • ......

这些数据单独拿出来是没有意义的,只有合在一起才能描述一个人,能不能将上面的数据类型整体的封装起来,用来描述一个复杂的对象。

-- 结构体 struct

对于基本类型、指针类型都是固定大小的;对于数组/结构体数据类型的大小是不固定的,成为构造类型。

9.2语法

构建

struct 结构体名
{
    成员类型1 成员变量1;
    成员类型2 成员变量2;
    成员类型3 成员变量3;
    ...
    成员类型n 成员变量n;
};

struct person
{
    char name[100];
    char sex;
    char nation;
    char id[20];
    int age;
};
  • struct person是构建了一个类型
  • 结构体名,成员变量名 要符合C语言标识符命名规则

通过构建了一个结构体类型后,就可以通过该类型来定义结构体变量了。

定义

struct person human;
//或者在构建结构体时也可以定义变量
struct person
{
    char name[100];
    char sex;
    char id[20];
    int age;
} human;

访问结构体变量成员

//使用结构体变量访问
humen.sex = 'f';
humen.age = 18;
strcpy(human.name, "hong");
//使用结构体指针访问
(&human)->sex = 'f';
(&human)->age = 18;
strcpy((&human)->name, "hong");
//定义一个指针指向humen
struct person *p = &human;
p->sex = 'f';
p->age = 18;
strcpy(p->name, "hong");

结构体数组

struct person human[] = {
    {"hong", 'f', "316546543", 18},
    {"ming", 'm', "654616541", 18}
};

结构体类型的大小

struct t
{
    int a;
    char b;
    short c;
};

struct t tt;	// sizeof(tt) == 8;
  • 结构体中规定成员变量的地址要能被它所占的内存大小整除
  • 整个结构体数据的字节大小要被它的每个成员变量中最大的基本类型整除(如果不能将进行字节填充)
  • 如果结构体中有构造类型,把组合类型拆开看

字节对齐有利于CPU寻址/取数据效率更高(一些内存较为紧张,且对速度要求不太高的情况,可以采用不对齐的方式)

9.3位域与柔性数组

9.3.1位域

如果定义int/char来表示少数几种状态,其实是一种浪费,在结构体中,位域就是用来合理利用内存,实现用位数表示状态。

9.3.2柔性数组

int a[10];

a的空间已经被定义好了,不能扩容

如果我们想在结构体中保存一串字符,定义如下

struct t1
{
    int n;			//保存字符串长度
    char c[100];	//保存字符
};

数组的大小不方便改变

解决方法 -- malloc

struct t1
{
    int n;		//保存字符串长度
    char *p;	//指向保存字符的空间
};

struct t1 *t = malloc(sizeof(*t));
//保存一个字符串:"xiaoming"
t->n = strlen("xiaoming")+1;
t->p = malloc(t->n);
strcpy(t->p, "xiaoming");
//不需要了就free
free(t->p);
free(t);
  • 这种方法繁琐且不安全,free时容易漏掉t->p
struct t1
{
    int n;		//保存字符串长度
    char p[0];	//柔性数组
};
//柔性数组元素个数为0,但是数组名任然表示一个地址,不占空间
//保存一个字符串:"xiaoming"
struct t1 *t = malloc(sizeof(*t) + strlen("xiaoming")+1);
t->n = strlen("xiaoming")+1;
strcpy(t->p, "xiaoming");
free(t);
  • 柔性数组要位于结构体其他成员末尾
  • 柔性数组前一定要有其他非柔性数组成员
  • 柔性数组的好处:减少内存碎片

10.联合体

联合体也是构造类型,关键字 union

语法

定义

union 联合体名
{
    成员类型1 成员变量1;
    成员类型2 成员变量2;
    成员类型3 成员变量3;
    ......
    成员类型n 成员变量n;
};
//示例
union test
{
    int a;
    char b;
};
  • 联合体定义语法与结构体类似

引用

union test t;
t.a = 10;
  • 联合体访问与结构体类似

联合体多个成员变量共同使用同一块内存,各个成员的地址是一样的

联合体适用于各个成员变量不同时使用的情况,且保存的数据类型各不相同,比结构体更省空间

联合体可以用来判断大小端

  • 大端存储方式:低字节存放在高地址
  • 小端存储方式:低字节存放在低地址

那么如何判断大小端呢

union test
{
    int a;
    char b;
};

int main()
{
    union test t;
    t.a = 0x12345678;
}
//如果t.b中的值为0x78,则为小端模式,否则为大端模式

共用体所占字节数

  • 最大成员变量决定至少要多少个字节
  • 对齐方式 成员变量中最大的类型
  • 组合类型拆开看

11.枚举

把该类型的数据的所有可能的值都列出来,该类型数据的值只能是列举出来的值(整数)

假设要描述一下星期一到星期日

0 -- 星期日

1 -- 星期一

2 -- 星期二

......

int day = 0;	//表达并不具体
int day = sunday;//见名知义,可以用枚举实现

语法:

定义

enum 枚举名
{
    枚举成员1 {=初始值},
    枚举成员2 {=初始值},
    枚举成员3 {=初始值},
    ......
    枚举成员n {=初始值}
};

//示例
enum week
{
    sunday = 0,
    Monday,
    Tuesday,
    .....
};
  • 枚举成员不是变量,但是要符合C语言标识符命名规则
  • 枚举成员代表一个值,是那个值的另外一个名字
  • 枚举成员的初始值可以选的,如果不选择,最开始的默认为0,后面的依次+1

12. typedef关键字

作用:给一个类型取新的名字。

示例

typedef unsigned int uint;	//将unsigned int取一个新名字uint
uint a;//等价于 unsigned int a;

12.1 typedefstruct

typedef struct test
{
    ....
} testDef;	//这时就可以用testDef来代替struct test

typedef struct
{
    ....
} testDef;	//也可以这样,这样就只能用testDef来定义结构体变量了

12.2 typedef和函数指针

typedef void *(*pFunc)(char *, char *);
//此时pFunc可以代替void *(*)(char *, char *)

12.3 typedef#define的区别

#define uint8 unsigned char	//用uint8代替unsigned char,在预处理之后,会将uint8替换为unsigned char
typedef unsigned int uint32;//uint32代替unsigned int
//-------
#define Pint int *
Pint p1,p2;//==>int *p1,p2;p1是一个指针变量,而p2是普通变量
typedef Pchar char *;
Pchar p1,p2;//==> char *p1, *p2;p1 p2都是指针变量
  • #define是简单替换,不做类型检查
  • typedef是给类型起别名
  • 给类型起别名用typedef

13.C程序组成

一个完整的工程,是由多个.c.h文件构成的

  • .c 保存源代码
  • .h 头文件

13.1 .c文件的组成

13.1.1头文件包含

#include <***.h>	//系统头文件
or
#include "***.h"	//自定义都文件

作用:在预处理时,将头文件在该位置展开,可以使用预处理命令gcc -E ***.c -o ***.i

对于 #include <***.h> ,编译器时怎么知道这个文件在哪里的 -- 环境变量,每个系统都有环境变量,它指定了编译器,头文件,库文件等重要文件的路径

<>" " 的区别

  • <> 表示头文件通过环境变量所指示的路径去查找
  • " " 头文件会限制当前工程指定的路径去查找,默认当前文件夹,如果该目录下没有该头文件,就会去环境变量所指示的路径去查找

13.1.2宏定义

关键字 #define

语法

//不带参数
#define 宏名 表达式
/*例如*/ #define pi 3.14
//作用:在预处理时,将宏名全部替换为表达式

//带参数
#define 宏名(参数) (表达式)

13.1.3声明

函数声明:

  • 在本文件中的函数

    void func();
    
  • 在同工程中其他文件中的函数

    extern void func();
    

变量声明:

  • 在本文件中的变量

    int a;
    
  • 在同工程中其他文件中的变量

    extern int a;
    

类型声明:

类型的声明/定义只在只在本文件中有效,一般放在头文件中

13.1.4条件编译

有选择地进行编译

#if 表达式
	功能代码;
#endif
/*
如果表达式为真,则编译这段代码
*************/
#if 表达式
	功能代码1;
#else
	功能代码2;
#endif
/*
如果表达式为真,则编译功能代码1
否则编译功能代码2
*************/
#ifdef 宏名	//理解为 #if define
	功能代码;
#endif
/*
表示如果#define了这个宏,则编译这段代码
*************/
#ifndef 宏名	//理解为 #if no define
	功能代码;
#endif
/*
表示如果没有#define这个宏,则编译这段代码
*/

13.2 .h文件的组成

一般一个项目/工程 实现起来代码量大,逻辑复杂,如果写在一个.c文件中,不易维护,可读性差,不易分工,所以要将不同模块的功能代码放在不同的.c 文件中

为什么需要.h文件呢?

.c.h 一般时一一对应的,一个模块有一个.C 来体现,也要有一个.h文件做辅助

.h文件更像是一个说明书,可以将各种功能的实现和声明进行隔离

13.2.1条件编译

/* stdio.h */
#ifndef _STDIO_H_
#define _STDIO_H_
...
#endif
//防止头文件的重复包含

13.2.2函数声明

作业

1.将各种排序卸载不同的.c文件中,通过main.c去调用这些排序

2.定义一个学生信息结构体类型,并定义该类型变量,输入10个学生的成绩,并输出分数最高的学生成绩结构体数据

3.在图书馆中,有很多种的书籍--漫画、科幻..... 设计相应的结构体,并设计一种结构可以保存所有种类书籍的信息

标签:typedef,struct,int,成员,C语言,char,变量
From: https://www.cnblogs.com/aalynsah/p/17548739.html

相关文章

  • C语言库函数
    C语言库函数1.stdio库1.1printf函数printf格式化输出符:inta=3;floatb=3.14;doublec=5.2;chars1[6]={'h','e','l','l','o','\0'};char*s2="world";printf("%d%f%f\n",......
  • C语言-00
    初识C语言//单行注释/*多行注释1.语言发展历程二进制的指令-->汇编指令-->B语言-->C语言(高级语言)2.C语言国际标准:ANSIC---美国国家标准化组织CC89C90C99C11...3.C语言是一门编译型语言,而Pytho......
  • 关于C语言中的《scanf》和《printf》函数的返回值
    一,scanfC语言中的scanf函数的返回值类型是int,表示你正确输入参数的个数代码如下:#include<stdio.h>intmain(){ inta=0; intb=0; intnum=scanf("%d%d",&a,&b); printf("num=%d\n",num); return0;}一,printfC语言中的printf函数的返回值类型是int,表......
  • C/C++2022级C语言课程设计任务书[2023-07-06]
    C/C++2022级C语言课程设计任务书[2023-07-06]2022级C语言课程设计任务书【题目1】学籍管理系统一、设计题目学籍管理系统(用动态结构体数组实现)二、设计内容【题目描述】假设某校学生学籍基本信息主要包括:学号(整型)、姓名(字符数组型)、所在系、班级等,本系统应能对这些......
  • c语言碎碎念(未完待续)
    %g格式符的使用这个格式符可以让浮点数自动舍去后面多余的0做题2.注意传递数组和传递指针的区别一个重要理解: int(*p)[4]; int**m; intb[4]; p=&b;// p=b;b==&b[0]即数组名==数组的第一个元素的地址!=数组的地址,若想获取数组的地址还要在数组名前加&//所以......
  • C语言工厂模式
    前言​ 工厂模式是在软件设计中常常使用一种设计模式。​ 在使用工厂模式进行软件开发,在创建对象的过程中,不会对客户端暴露具体的逻辑实现,而是使用一个共有的接口来指向创建的对象。通过这样的方式进行软件开发好处是,可以在不修改原本的代码的基础上加入新的产品,满足软件设计的......
  • c语言学习3
    一、for循环语句循环:就是一种让一段代码反复执行的方式,从而达到想要的效果for循环一般会使用一个变量来引导循环的进行,这个变量叫做该循环的循环变量iindexfor循环的变化很灵活,但也很危险(相比于其他循环)for([1];[2];[3]){[4]}[1]、给循......
  • C语言中 #pragma pack()
    #pragma pack    这条指令主要用作改变编译器的默认对齐方式。 pragmapack(show)     //显示当前内存对齐的字节数,编辑器默认8字节对齐   #pragmapack(n)        //设置编辑器按照n个字节对齐,n可以取值1,2,4,8,16   #pragmapack(push)  ......
  • c语言学习2
    一、数据类型为什么要对数据进行分类?1、现实中的数据就是自带类别属性的2、对数据进行分类可以节约内存存储空间、提高运行速度存储空间的单位:Bit比特存储一个二进制位,只能存储0或者1,计算机存储数据的最小单位Byte字节存储八个二进制位,计算机存储数据的基本单位Kb102......
  • 如何用C语言实现多态?
    多态(Polymorphism)是指面向对象程序运行时,相同的消息可能会送给多个不同的类之对象,系统依据对象所属类,引发对应类的方法,而有不同的行为。简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作。在C语言中,可以通过结构体和指针来实现多态。以下是通过结构体和指针实现多态......