C语言参悟-数据类型

C语言的数据类型

  • 一、概述
  • 二、基础数据类型
    • 1. 整数
      • 1. 计算
      • 2. 索引
    • 2. 浮点数
    • 3. 字符
    • 4. 字符串
    • 5. 指针
  • 三、特殊数据类型
    • 1. 枚举
    • 2. 共用体
    • 2. struct结构体
  • 四、数据类型修饰符
    • 1. const
    • 2. unsigned、signed

一、概述

编程语言为抽象这个物理世界提供了依据,其中对于描述物理世界的情况提供了一个叫做数据类型的名字,这种数据类型是我们人类能够认识的东西,就像数字,字母,字符之类的。

C语言中也提供了数据类型这种说法,就像下面的图片里面猴子,我们用C语言描述图片里面的猴子,就可以用 C语言里面的 字符串 数据类型来描述:

char * imageDescription = "两只猴子,一个大猴子,一个小猴子";

在这里插入图片描述
下面是我对 C语言里面的数据类型的理解使用参悟。

二、基础数据类型

1. 整数

C语言里面的整数类型标识符就是:int, long, long longshort,就行 0,-1,-23,4235 等等,也就是不带小数的整数。最常用的是 int。 long, long long适合大场景的整数 ,相对于整数只是存的数值范围比较大而已,属性基本一致,后面我都是用int来举例代表整数的。short 就是使用时相对较小的索引范围值而已。在后面会有一个专门的表去归纳这些变量的内存模型。

C语言里面的整数用处很多,因为计算内部都是用二进制表示数据的,里面的数据本质上都是整数的,浮点数也是用二进制整数去描述的。整数有很多的性质都十分有用,比如整数除法的结果也是整数等等。整数在计算之外的最大用处就是索引,在数组、循环、判断、地址索引等场景都是用的整数去做的。

1. 计算

声明一个 int 变量也很简单的,直接是 int 变量名;如果没初始化默认是给的一个随机值,一定要记得初始化哈。因为在像循环的时候,总是得从一个有效的开始索引进行索引,如果没设置好值,这就会出问题,就会出现段错误。

C语言整数一个很有用的计算就是 除法, 而且 取余 运算只能 整数 哦

就像下面,除法会把除出来的数的小数部分给抛掉,只保留整数部分

// 声明变量并初始化,初始化就使用 = 
int i = 0;i = 1 / 2;	//i = 0

取余 运算也是很简单的

int i = 11;i = i / 2;	//i = 0

对应 最经典便是 个十百位

#include <stdio.h>int main()
{int numA, numB, numC, numD;printf("请输入一个三位数: ");scanf("%d", &numA);numA = (int)numA;numD = numA % 10;numC = (numA / 10) % 10;numB = numA / 100;printf("这个三位数的个十百分别为:%d %d %d",numD, numC, numB);return 0;
}

2. 索引

数组的本质其实就是一个数据表,一维数组就是单行表,二维数组就是多行表,整数在索引的时候其实就可以当一个表示位置的强大工具。

就像下面的一个二维数据表就是用的 行 - 列 来确定位置的,这里用浮点数明显就是不行的。

表[ 行索引 ][ 列索引 ] 来确定一个位置的值
在这里插入图片描述

int martx[3][3] = {{0, 1, 2}, {4, 5, 6}, {7, 8, 9}};

对于上面的 martx 数组, 我们要取得 第 2 行,第 1 列的数据就是使用 martx[1][0]

最灵活的莫过于 对这个 索引 的变化。

2. 浮点数

浮点数其实就是 小数,对了科学计数法的写法也是浮点数类型哈。

在C语言里面的 浮点数的类型就是 float, double 两个类型,其实就是一个精度低,精度高的区别,一般使用double的多些。

对于这个的使用其实并不会太过多的考虑,但是要考虑到一个就是在 他和其他数据运算的时候,有他就会让数据的类型往浮点数靠

就像 7+7.32 的结果 就是浮点型
但 7+7 的结果就是 整型

3. 字符

C语言里面的字符主要是指英文字符,类型使用 char 表示。

声明就像下面的格式声明,用单引号来包括一个字符,这些字符全是 ASCII字符哈,也就是下面的 3,4 表格里面的所有值,其实char 也是一种特殊的int类型,他也是用的整数表达字符。

字符的比较大小其实也就是比较 对应 的 ASCII 的码值哈。

char 的大小就是 1个字节,刚好表示 128个数

char ch = 'A';

对应这个表格之外的字符就不是 ASCII 的编码了,那就不能用 char 来表示
就像下面表示中文字符就是不对的:

char  sc = '张';

中文字符是用的 Unicode 编码,就是两个字节,但char只有一个字节的大小,所以用不了,编译器就会对这个报错

那存储中文以及其他字符的话就得用 字符串去描述了。

3. 控制字符
ASCII控制字符的编号范围是0-31和127(0x00-0x1F和0x7F),共33个字符。
在这里插入图片描述
4. 可显示字符
可显示字符编号范围是32-126(0x20-0x7E),共95个字符。
在这里插入图片描述

4. 字符串

字符串本质上就是就是一种数据,是 一系列连续的字符构成的连续串,因为字符串这种数据类型在实际项目中使用的是非常多,因为这个是和人类的文字语言是最接近的一种格式,正如你所看到的内容便是 由字符构成的字符串数据。

因为存储的需要,指针和字符串是密不可分的,就需要把把指针和字符串结合起来一起看最好。

5. 指针

指针就是一个数据类型,专门存放其他变量的地址的一个类型。指针是一个很大内容,有兴趣可以看看我的笔记

指针入门基础
C的动态内存管理
指针与函数
指针和数组
指针与字符串

三、特殊数据类型

1. 枚举

枚举类型其实就是 一种为了简化编程命名的类型。用于定义一组具有离散值的常量。它可以让数据更简洁,更易读。

枚举类型通常用于为程序中的一组相关的常量选项取名字,以便于程序的可读性和维护性。

就像我们定义一组颜色的表示,可以用宏定义来做

#define 0 Red
#define 1 Green
#define 2 Blue
#define 3 Yellow

当然更推荐使用 枚举 来做,这样更好维护,下面一看就知道是Color里面的某个值,比较宏定义只是简单的替换,不会去检查值的正确性。但数据类型就不一样了,数据类型就会被严格的检查的。

就行下面的声明调用

enum Color
{Red,Green,Blue,Yellow
};//声明一个变量,要带enum 关键字
enum Color m_color = Color.Red;

更推荐 搭配 typedef 一起使用

typedef enum Color
{Red,Green,Blue,Yellow
}CColor;//声明一个变量
CColor m_color = CColor.Red;

当然,枚举类型也是有值的哈,而且是整数的,这就意味着可以用 switch 的方式去判断

默认从0开始,依次递增,就像Red 值是0,Green = 1, Blue = 2 等等。

如果手动设置值,那后面的值就在那个设置的值基础上自动加 1

当然也可以这样写

enum Color
{Red,Green = 4,Blue,Yellow
};

Red 默认从0开始,依次递增,因为Green 手动设置为值是4,那后面的依次递增 Blue = 5, Yellow = 6 等等。
这个属性知道就可以啦,不用强制明白。

2. 共用体

共用体是一种特殊的数据类型,可以在相同的内存位置存储不同的数据类型。但是数据在内存一个时间点里面只有一种类型哈

我们可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。

共用体提供了一种使用相同的内存位置的有效方式。

union Data
{int i;float f;char  str[20];
} ;union Data m_Data;

我们也可以用typedef简化定义

typedef union Data
{int i;float f;char  str[20];
} Un_Data;Un_Data m_Data;

现在,Data 类型的变量可以存储一个整数、一个浮点数,或者一个字符串。这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。我们可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型

共用体占用的内存应足够存储共用体中最大的成员

就像上面的,Data 将占用 20 个字节的内存空间大小,不管存int, float 还是 char*;

2. struct结构体

struct结构体 C语言给我们提供的一个开放的定义自己的 数据类型 的一个强大工具,我们可以用 struct 去描述一个数据结构,在这个结构里面用的就是上面提到的数据类型,当然也是包括在结构体内再存结构体的。

举个例子:我们用一个结构体描述一个位于屏幕上的圆的数据。

这个圆有半径,圆有相对屏幕左上角坐标位置,圆还有外围圆的线宽,外围线的颜色,内圆的填充颜色等数据。

1. 定义结构体

struct 结构体名称{内部类型} ;

在使用的时候就是把 struct 结构体名称 当成一个自定义的类型使用就好,就像 int 一样的使用。

那定义一个这样的圆可以这么写

// 颜色结构体
struct color{short red;short green;short blue;
};// 位置
struct point{int x;int y;
}// circule
struct circule{int Radius;struct point Point;struct color OuterColor;struct color InnerColor;
}

但是这种写法可能有点夯长,那我们就可以用 typedef 来把这个结构体命名一样,命名成我们更加可读的 变量类型名称。

typedef 类型 自己想要的类型名

可以就把上面的代码改写一下

struct color{short red;short green;short blue;
};//定义别名
typedef struct color ST_Color;// 位置
struct point{int x;int y;
};typedef struct point ST_Point;// circule
struct circule{int Radius;ST_Point Point;ST_Color OuterColor;ST_Color InnerColor;
};typedef struct circule ST_Circule;

当然我们还可以直接用 typedef 去简化定义,在什么结构体的时候就给命别名

typedef struct color{short red;short green;short blue;
} ST_Color;

2. 使用结构体

结构体的使用同样也是很简单的,就和普通的类型一样,只是在访问结构体内部成员的时候要用 ‘.’ 符号访问而已

下面我就声明一个圆形的结构体

// 声明结构体
ST_Circule m_circlue;
ST_Circule *p_circle = NULL;// 初始化结构体
m_circlue.Radius = 10;
m_circlue.Point = {0,0};	//这种是是用列表初始化
m_circlue.InnerColor = {12,23,34};m_circlue.OuterColor.blue = 12;	//这种是每个单独的去初试化
m_circlue.OuterColor.red = 23;
m_circlue.OuterColor.green = 34;//在使用结构体指针的时候,为了区分是指针所有还是用的变量名索引,在访问结构体成员变量的时候会用 -> 来区分
p_circle = &m_circlue;
printf("m_circlue-Radius: %d", p_circle->Radius);

3. 内存布局
结构体内存大小理论上是和其内部所有成员内存大小之和。而且成员的内存排列顺序一定是定义顺序。

在这里插入图片描述

理论上讲结构体的各个成员在内存中是连续存放的,和数组非常类似,但是,结构体的占用内存的总大小不一定等于全部成员变量占用内存大小之和。在编译器的具体实现中,为了提高内存寻址的效率,各个成员之间可能会存在缝隙。

就像 ST_Circule 的理论大小是 24 字节。就是连续的。

在结构体里面其实是并非完全的内存连续,就是其实是有内存对齐的。

默认的字节对齐原则

首先引出一个概念自然对齐(naturally aligned),是指数据的起始地址是该数据类型大小的倍数。结构体的对齐是指其中的每个数据成员都是自然对齐的,要达到这个效果可能需要在成员之间进行必要的字节填充。比如一下struct:

struct Struct {char c1; // 1Buint64_t n1; // 8B
};

在默认情况下需要在c1后面填充7个字节,才能保证n1是自然对齐的。此时sizeof(DemoStruct)==16

C/C++ struct通常的对齐原则如下:
保序:
在保序的基础上保证每个成员是自然对齐的,如果前一个成员紧接着的地址不满足对齐要求,则增加填充。
最后一个成员后面也可能会增加填充,这样能保证创建struct数组时,数组中的每个struct仍然是对齐的。
结构体嵌套时,递归的按照结构体中最大的那个成员对齐。(注意不是最大的结构体,而是结构体总最大的那个成员

pragma pack(1)抹除填充

我们可以通过#pragma pack(1)来强制struct不增加填充,比如如下struct:

#pragma pack(1)
struct DemoPackStruct {char c1; // 1Buint64_t n1; // 8B
};

由于强制改成了1字节对齐,所以上述结构体中无需填充。此时sizeof(DemoPackStruct)==9。

这么做的主要目的就是节省内存,以损失访存效率为代价。可能还有一个作用是方便数据结构的网络传输,比如直接免去序列化过程将整个数据结构通过网络发送,但这么做并不保险,因为不同机器之间存在字节序的问题(大端/小端,endianness)。

当然也可以给指定更大的pack值,以强制struct按更大的字节对齐,比如以下数据结构 sizeof(DemoPack2Struct)==10:

#pragma pack(2)
struct DemoPack2Struct {char c1; // 1Buint64_t n1; // 8B
};

使用pack需要注意以下几点:

pack(n)的值必须是2的指数,比如n可以是1,2,4等

pack只能用于减少sturct的padding,不能用于增加padding。比如一个struct中最大的成员是8字节,那么pack(16)不起任何作用。

#pragma pack()影响这条语句之后的所有struct声明,可通过pack(push), pack(pop)保存和恢复之前默认的pack

四、数据类型修饰符

1. const

2. unsigned、signed

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/62259.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

桂林小程序https证书

现在很多APP都相继推出了小程序&#xff0c;比如微信小程序、百度小程序等&#xff0c;这些小程序的功能也越来越复杂&#xff0c;不可避免的和网站一样会传输数据&#xff0c;因此小程序想要上线就要保证信息传输的安全性&#xff0c;也就是说各种类型的小程序也需要部署https…

个推消息推送专项运营提升方案,基于AIGC实现推送文案智能生成

个推消息推送专项运营提升方案自今年3月份发布以来&#xff0c;已应用于游戏社交、影音资讯、电商购物等多个行业。现个推消息推送专项运营提升方案又实现了推送策略的智能化和推送流程的自动化&#xff0c;助力APP进一步提升消息推送的效率和效果。 丰富推送策略组合&#xf…

【Spring Boot】Thymeleaf模板引擎 — Thymeleaf页面布局

Thymeleaf页面布局 熟悉Thymeleaf的语法和表达式后&#xff0c;后面开发起来会更加得心应手。接下来好好研究一下Thymeleaf如何实现完整的Web系统页面布局。 1.引入代码片段 在模板中经常希望包含来自其他模板页面的内容&#xff0c;如页脚、页眉、菜单等。为了做到这一点&a…

华熙生物肌活:2023年版Bio-MESO肌活油性皮肤科学护肤指南

关于报告的所有内容&#xff0c;公众【营销人星球】获取下载查看 核心观点 以悦己和尝鲜为消费动机的他们&#xff0c;已迅速崛起成为护肤行业的焦点人群。而在新生代护肤议题中&#xff0c;“油性皮肤护理”已经成为一个至关重要的子集。今天&#xff0c;中国新生代人口数量…

【学习日记】【FreeRTOS】临界段的保护

写在前面 本文主要是对于 FreeRTOS 中临界段的保护的详细解释&#xff0c;代码大部分参考了野火 FreeRTOS 教程配套源码&#xff0c;作了一小部分修改。 一、什么是临界段 临界段就是一段在执行的时候不能被中断的代码段。 **临界段&#xff08;Critical Section&#xff0…

事务和事务的隔离级别

1.4.事务和事务的隔离级别 1.4.1.为什么需要事务 事务是数据库管理系统&#xff08;DBMS&#xff09;执行过程中的一个逻辑单位&#xff08;不可再进行分割&#xff09;&#xff0c;由一个有限的数据库操作序列构成&#xff08;多个DML语句&#xff0c;select语句不包含事务&…

【ASP.NET MVC】使用动软(二)(10)

一、添加动软生成工程 按前文添加动态到工程 双击动软 完成新建数据库服务器后 &#xff0c;需要关闭重新打开 选择简单三层&#xff0c;注意保存位置 注意切换数据库&#xff1a; 生成后拷贝五个文件夹到工程目录 注意目录结构&#xff1a; 添加四个项目到原来的工程&…

基于云平台的智慧养殖远程监控系统

一、项目背景 冬春季节每天的温度和昼夜温差变化很大&#xff0c;为保证养殖动物有一个温暖舒适的生存环境&#xff0c;使动物的生产性能得到较好的发挥&#xff0c;须注意做好温度、湿度、通风等方面的控制。 智慧养殖智能监控系统可以实现对如温度、湿度、气体浓度、光照度…

关于接口自动化,你不能不知道的高级技巧——接口自动化神器apin进阶操作

一、变量提取和引用 变量提取和引用主要是为了解决接口之间的参数依赖问题。 使用场景&#xff1a;接口 A 的参数中需要使用接口 B 返回的某个数据&#xff0c;那么就要在请求 B 接口之后&#xff0c;提取数据保存&#xff0c;给请求 A 接口时使用。 1、变量提取 在用例集或…

绝了!学编程的还有不知道的吗?这个Java开发工具免费了!

智能开发正在迅速走红&#xff01; 随着ChatGPT的广泛应用&#xff0c;智能开发越来越受到关注。然而&#xff0c;实际上&#xff0c;在数年前开始尝试智能开发的探索。 自从2014年ForresterResearch提出"低代码"的概念以来&#xff0c;低代码平台的发展非常迅速。…

非计算机科班如何丝滑转码?

近年来&#xff0c;很多人想要从其他行业跳槽转入计算机领域。非计算机科班如何丝滑转码&#xff1f; 如何规划才能实现转码&#xff1f; 对于非计算机科班的人来说&#xff0c;想要顺利转码成为计算机相关岗位的从业者&#xff0c;需要经过以下几个步骤&#xff1a; 规划转码…

[JAVAee]网络编程-套接字Socket

目录 基本概念 发送端与接收端 请求与响应 ​编辑客户端与服务器 Socket套接字 分类 数据报套接字 流套接字传输模型 UDP数据报套接字编程 DatagramSocket API DatagramPacket API InetSocketAddress API 示例一: 示例二: TCP流数据报套接字编程 ServerSock…