c++ byte转cbitmap_C开发实战-变量和数据类型

计算机的计算单位

容量单位

在购买电脑时,通常会选择高配置的内存、硬盘。

c87b064a0b696c891d0cd4f4f8bf1e91.png


例如2020款16寸的MacBookPro已经可以选配64G内存和8T的固态硬盘,而这里的64G和8T就是计算机常用的容量单位。

在物理层面,我们使用高低电平来记录信息,通常使用高电平表示1,低电平表示0,因此在计算机底层只能认识0,1两种状态。而0,1能够表示的内容太少,迫切需要更大的容量表示方法,因此诞生了字节(Byte),千字节(KB),兆字节(MB),吉字节(GB),太字节(TB),拍字节(PB),艾字节(EB),除了bit和Byte之外,从Byte到KB,MB,GB,TB,PB,EB,它们的换算都是以2的10次方即1024换算的。

1YB=1024ZB1ZB=1024EB1EB=1024PB1PB=1024TB1TB=1024GB1GB=1024MB1MB=1024KB1KB=1024B1Byte=8bit
  • 位(bit)是最小的计算机容量单位,通常用于门电路,只能存储0或者1
  • 字节(Byte)、千字节(KB)、兆字节(MB)表示网络传输以及文件大小。字节是最基本的容量计量单位,一个字节能存储255个数据。
  • 吉字节(GB)通常用于表示计算机内存、磁盘的容量单位
  • 太字节(TB),拍字节(PB)通常是用于表示云盘、移动硬盘的容量单位
  • 艾字节(EB)通常是用于表示数据中心的容量单位

现在通常笔记本的内存通常是16G,32G,64G等等,而运行在笔记本之上的操作系统普遍都是64位的,因为32位系统只能使用4G内存,下面是4G的内存换算

4G=2^2 - 2^10 - 2^10 - 2^10 =4*1024*1024*1024=2^32

在购买内存或者买移动硬盘时,通常使用的存储单位就是GB或者是TB,
但是在买4T的移动硬盘时,实际的可用容量却只有3T多,因为计算机的存储单位是以2的10次方(即1024)换算,而硬盘厂商们是以10^3(即1000)为换算单位。

4T的硬盘换算成位如下所示

4T=4*1024GB*1024MB*1024KB*1024B*8bit

而硬盘厂商的实际容量

4T=1000*1000*1000*1000*8bit

因此实际的可用容量是

4*1000*1000*1000*1000/1024/1024/1024/1024≈3.63T

而在一些互联网巨头(例如国内的BAT、ATM,国外的亚马逊、苹果、微软、谷歌,脸书)公司中,可能使用到比TB更大的海量数据,也就是PB或者EB,它们的换算单位如下所示。

1PB=1024TB1EB=1024PB

速度单位

网络速度

网络常用的单位是Mbps
而网络带宽提供商(例如长城宽带)声称的百兆带宽实际上是100Mbit/s,但是100M光纤测试的峰值速度只会有12.5MB/s,它们之间的换算是100Mbit/s=(100/8)MB/s=12.5MB/s。

CPU速度

CPU的速度一般是由CPU的时钟频率所体现的,而时钟频率的单位是赫兹(Hz),目前主流的CPU时钟频率一般都在2GHz以上,而赫兹(Hz)其实就是秒分之一,也就是每秒钟的周期性变动重复次数的计量。
GHz即十亿赫兹(10^9Hz),2GHz就是二十亿赫兹,也就是说2GHz的CPU每秒可以变化20亿次。

1Khz=1000Hz1Mhz=1000KHz1Ghz=1000MHz

计算机进制及其转换

计算机进制介绍

进制的定义:进制是一种计数方式,也称为进位计数法或者位值计数法,使用有限数字符号表示无限的数值,使用的数字符号的数目称为这种进位制的基数或者底数,例如十进制就是由0-9十个数字组成。在计算机内存中,都是以二进制的补码形式来存储数据的,生活中以十进制方式计算的数据居多,例如账户余额,开发人员的薪水等等。而 计算的内存地址、MAC地址等等通常都是使用十六进制表示的,Linux的权限系统采用八进制的数据表示的。相同进制类型数据进行运算时会遵守加法:逢R进1;减法:借1当R,其中R就表示进制。

计算机常用进制的组成、示例和使用场景

进制名称组成数值示例应用场景二进制0,11010计算机内部数据表示八进制0,1,2,3,4,5,6,7010Linux权限系统十进制01,2,3,4,5,6,7,8,912整数十六进制0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f12f数据的内存地址

计算机底层为什么只能识别二进制

我们目前主要使用的计算机都是大规模集成电路,是采用大规模和超大规模的集成电路作为逻辑元件的。集成电路按其功能、结构的不同,可以分为模拟集成电路、数字集成电路和数/模混合集成电路三大类。而我们的计算机主要是采用数字集成电路搭建的。逻辑门是数字逻辑电路的基本单元。常见的逻辑门包括“与”门,“或”门,“非”门,“异或”等等。通过逻辑门可以组合使用实现更为复杂的逻辑运算和数值运算。逻辑门可以通过控制高、低电平,从而实现逻辑运算。电源电压大小的波动对其没有影响,温度和工艺偏差对其工作的可靠性影响也比模拟电路小得多,所以相对稳定。因为数字计算机是由逻辑门组成,而逻辑电路最基础的状态就是两个:开和关。所以,数字电路是以二进制逻辑代数为数学基础。二进制的基本运算规则简单,运算操作方便,这样一来有利于简化计算机内部结构,提高运算速度。但是在日常开发中,通常都会使用八进制和十六进制,因为八进制和十六进制相对于二进制表示数据更加简洁,而且一个八进制表示三个二进制,一个十六进制表示四个二进制。例如1024使用二进制表示为0b100 0000 0000,使用八进制表示为02000,使用十六进制表示为0x400。

十进制转二进制、八进制、十六进制

十进制转换二进制、八进制、十六进制可以采用短除法,即待转换的十进制数除以指定的进制(例如2,8,16),直到商数为0,求余数。

十进制101转换为二进制的计算过程

重复除以2商数余数101/250150/225025/212112/2606/2303/2111/201

然后将余数的结果从下到上串联起来的结果:1100101,即十进制的101转换为二进制的结果为1100101

十进制的237转换为二进制

重复除以2商数余数237/21181118/259059/229129/214114/2707/2313/2111/201

然后将余数的结果从下到上串联起来的结果:11101101,即十进制的237转换为二进制的结果为11101101。

除了短除法以外,如果掌握了常见的十进制数对应的二进制数

科学计数法十进制二进制2^0112^12102^241002^3810002^416100002^5321000002^66410000002^7128100000002^82561000000002^951210000000002^10102410000000000

在进行十进制转二进制时,还可以使用减法来转换
以十进制11转换为二进制为例,因为11介于16和8中间,而11-8=3,8的二进制表示为1000,3的二进制是11,而二进制的1000+11=1011,因此十进制的11转换为二进制的结果是1011

Windows系统中可以使用计算器(calc)来实现进制之间的转换

2529b7d1d48d9eb79c03aae3981e69c2.png

二进制、八进制、十六进制转十进制

首先明确不同进制的值是如何计算的,这里以十进制和二进制为例子,阐述它们的计算过程。

十进制整数1024

1024=1*10^3+2*10^1+4*10^0=1000+20+4=1024

二进制整数 10000000000

10000000000 =1*2^10=1024

二进制、八进制、十六进制整数转十进制整数是使用按权展开法计算的,这里以二进制数据01100101为例子。从右往左开始数,如果二进制位为1,则依次用1*2^n,n从0开始。

二进制整数01100101 转换为十进制整数的计算过程

01100101=2^6+2^5+2^2+2^0=64+32+4+1=101

八进制整数0127转换为十进制整数的计算过程

0127=1*8^2+2*8^1+7=64+16+7=87

十六进制整数0x12f转换为十进制整数的计算过程

0x12f=1*16^2+2*16^1+f*16^0=256+32+15=303

二进制的1011转换为十进制的计算过程

1011=1000+11=2^3+2^1+2^0=8+2+1=11

二进制转八进制、十六进制

二进制转八进制是按照从右往左,每3位二进制对应1位八进制,因为八进制最大的值是7,用三个二进制位表示1111。

二进制整数11001100转八进制计算过程

11 001 100 =0314

二进制转十六进制是按照从右往左,每4位二进制对应1位十六进制,因为十六进制最大的值是15,使用四个二进制位表示为1111。

二进制整数1100 1110转十六进制计算过程

1100 1110 =0xce

八进制、十六进制转二进制

八进制转二进制是按照从右往左,每1位八进制对应3位二进制。

八进制整数0127转二进制整数计算过程

0127=001 010 111

十六进制转二进制是按照从右往左,每1位十六进制对应4位二进制。

十六进制整数0x12f转换为二进制整数计算过程

0x12f=0001 0010 1111

数据类型

内存好比生活中常见的酒店,一家大型酒店按照房屋的面积大小有不同的房间,单人间、双人间、三人间、总统套房等等,每个房间都有唯一的房间编号。而内存也被划分成不同大小的内存空间来存储不同的数据类型,数据类型就是给数据按照占据内存大小来分类,从而实现合理的利用内存空间,提高存储效率。
C语言中的数据类型有基本数据类型和其他类型,其他类型都是由基本数据封装而来,不同的数据类型占据不同的内存大小,不同的取值范围以及能够参与不同的运算。
常用的基本数据类型有字符型(char)、短整型(short)、整型(int)、长整型(long)、长长整型(long long)、单精度浮点型(float)、双精度浮点型(double),C99编译器支持长长整型(long long),C99兼容C89。 其中char,short,int,long,long long默认是有符号类型,还有对应的无符号类型(unsigned)用于存储正数。
类型(char,short,int,long,float,double)是抽象的概念,类型有大小,但是没有内存空间,即系统不会给系统分配空间,只会给类型定义的变量分配空间。
C语言提供了sizeof(类型名/变量名)关键字来计算变量或者数据类型的大小,需要注意的是C语言的数据类型在32位系统和64位系统占据的内存空间是不一样的。

sizeof运算符

#define _CRT_SECURE_NO_WARNINGS#include #include /*sizeof运算符获取指定数据类型占据的字节数量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){printf("char 类型占据的字节数量是%d", sizeof(char));printf("short 类型占据的字节数量是%d", sizeof(short));printf("int 类型占据的字节数量是%d", sizeof(int));printf("long 类型占据的字节数量是%d", sizeof(long));printf("long long 类型占据的字节数量是%d", sizeof(long long ));printf("float 类型占据的字节数量是%d", sizeof(float));printf("double 类型占据的字节数量是%d", sizeof(double));system("pause");return 0;}

Visual Studio 2019提供了32位编译器和64位编译器,其中X86表示32位编译器,而X64表示64位编译器

834d9031a66690c20b3f38d8bc9e64af.png


在Windows平台下long类型无论是32位还是64位都是占据4个字节,而Linux或者macOS则是占据8个字节
int类型的整数占据4个字节,short类型的整数占据2个字节。而在Windows下long类型占据4个字节,64位Linux下占据8个字节。
char字符型的字节占据1个字节,用于存储单个字符,也可以存储一个字节的整数,是最小整数的内存单位。
float单精度浮点型,占据 4个字节,小数点后精确到6-7位
double双精度浮点型,占据4个字节,小数点后精确到15-16位。

有符号数和无符号数

有符号(signed)可以表示正整数、0和负数,而无符号只能表示0和正整数
以一个字节的char为例(因为char只占据1个字节,也就是八个二进制位,比较简单点),理解有符号和无符号在内存中的表示

有符号数的二进制位由符号位和数据位组成
例如有符号数 +1的二进制表示方式0000 0001,-1的二进制表示方式为1000 0001,左边的最高位表示符号位,0表示正数,表示负数,右边的7位表示数据位。

无符号(unsigned)数的二进制位由数据位组成,没有符号位
例如无符号数+1的二进制表示方式为0000 00001,其中最左边的0也是数据位。而二进制的无符号数1000 0001表示为十进制的整数是129

数据的取值范围

char的取值范围

有符号char(signed char)的取值范围

  • 负数 1000 0000 - 1111 1111 转换为十进制的结果是-0 到 -127
  • 正数 0000 0000 - 1111 1111 转换为十进制的结果是0到127
    而计算机底层规定 十进制的-0的表示为十进制的-128
    因此signed char的取值范围是-128到127,换算成科学计数法的表示方式为-27到28-1

无符号char(unsigned char)的取值范围

  • 正数 0000 0000 - 1111 1111 转换为十进制的结果是0-255的256个十进制整数

因此有符号数signed char和无符号数unsigned char 表示数据的数量是一样的,只是表示数据的范围不一样。

而C语言提供了常量来表示char的有符号和无符号的表示范围

short的取值范围

有符号short(signed short)的取值范围

  • 负数 1000 0000 0000 0000 - 1111 1111 1111 1111 转换为十进制的结果就是-0 到-32767
  • 正数 0000 0000 0000 0000 - 1111 1111 1111 1111 转换为十进制的结果就是0-32767

因为 两个字节的-0 表示为 -32768
因此signed short的取值范围是-32768到32767,换算成科学计数法的表示方式为-215到216-1

int的取值范围

有符号int(signed int)的取值范围

  • 负数 1000 0000 0000 0000 0000 0000 0000 0000 - 1111 1111 1111 1111 1111 1111 1111 1111 转换为十进制的结果就是-0 到-2147483647
  • 正数 0000 0000 0000 0000 0000 0000 0000 0000 - 1111 1111 1111 1111 1111 1111 1111 1111 转换为十进制的结果就是0-4294967295
    因为 两个字节的-0 表示为 -2147483648
    因此signed short的取值范围是-2147483648到2147483647,换算成科学计数法的表示方式为-231到232-1

针对不同类型(char,short,int,long,long long)的有符号、无符号整数,C语言定义了常量来表示它们的取值范围

#define _CRT_SECURE_NO_WARNINGS#include #include /*    有符号和无符号整数(char,short,int,long,long long)的表示范围@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){printf("有符号char的表示范围是从%d到%d",CHAR_MIN,CHAR_MAX);printf("无符号char的表示范围是从%d到%d",0,UCHAR_MAX);printf("有符号short的表示范围是从%d到%d", SHRT_MIN, SHRT_MAX);printf("无符号short的表示范围是从%d到%d", 0, USHRT_MAX);printf("有符号int的表示范围是从%d到%d", INT_MIN, INT_MAX);printf("无符号int的表示范围是从%d到%u", 0, UINT_MAX);printf("有符号long的表示范围是从%ld到%ld", LONG_MIN, LONG_MAX);printf("无符号long的表示范围是从%d到%u", 0, ULONG_MAX);printf("有符号long long的表示范围是从%lld到%lld",LLONG_MIN, LLONG_MAX);printf("无符号long long的表示范围是从%u到%llu", 0, ULLONG_MAX);system("pause");return 0;}

在使用对应数据类型时不要超过它们的范围,如果超过了就会造成数据溢出错误,执行程序会得到一个错误的逻辑。

#define _CRT_SECURE_NO_WARNINGS#include #include /*    整数的越界@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){char number = 127+2;printf("number = %d",number);system("pause");return 0;}

程序运行结果

9e4462d6b18be7c1bac1fdb7777fefa2.png

常量

常量就是在程序运行过程中,其值不能被修改的量,例如10就是整数常量,3.14就是浮点数常量,'a'就是字符常量,"hello world"就是字符串常量。常量值之所以不能被修改,是因为常量存储在内存的文字常量区,内存存储数据时除了按照数据占用不同的内存空间进行分类存储以外,还要考虑数据的特点,将内存分成各种区域,例如栈区、堆区、文字常量区、代码区、全局区。

常量不能被修改,所谓修改的含义就是不能被赋值,但是可以将常量值赋值给变量。

#define _CRT_SECURE_NO_WARNINGS#include #include /*    使用printf()函数结合字符串个师傅输出 C语言常用的常量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){    printf("char =%c", 'a');    printf("short =%hd", 10);    printf("int =%d", 100);    printf("long=%ld", 1000000);    //float单精度类型的常量以f结尾    printf("float = %f", 3.14f);    printf("double=%lf", 3.14);    //常量不能被修改,修改的含义就是不能被赋值    //10=20    //但是常量可以被取值,即将常量赋值给变量    //例如将整数常量10赋值给变量10    int age = 10;system("pause");return 0;}

C语言提供了两种常量的使用方式

  • #define宏定义常量
    宏定义常量的语法格式为 #define 常量名 常量值 例如#define MAX_VALUE 10
#define _CRT_SECURE_NO_WARNINGS#define  MAX_VALUE 10  //使用宏定义来定义常量#include #include /*宏定义来定义常量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//使用宏定义的常量printf("MAX_VALUE=%d",MAX_VALUE);system("pause");return 0;}
  • const常量
    const用于修饰变量。一旦使用const修饰的变量就不能使用变量名修改变量的值
#define _CRT_SECURE_NO_WARNINGS#include #include /*const常量和变量对比@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){int number = 10;//变量可以被修改number = 20;const int data = 10;//data = 20;// const修饰的变量不能通过变量名被修改,此处会出现编译错误system("pause");return 0;}

变量

变量概述

变量顾名思义就是在程序运行过程中,其值可以被修改。系统会根据变量类型,给变量开辟内存空间

#define _CRT_SECURE_NO_WARNINGS#include #include /*变量概述@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//10 表示常量//将常量值10赋值给变量numberint number = 10;// 变量定义的格式// 数据类型 变量名;//当变量定义后,系统会根据变量的类型开辟对应的内存空间//因为int是整型,默认占据4个字节,因此系统会给age变量开辟4个内存的空间//变量可以进行读写操作,读就是获取变量的值,写就是给变量赋值system("pause");return 0;}

任何变量都需要先定义、初始化、声明后再使用。
变量的定义就是让变量存在,系统会给变量开辟内存空间。
变量的声明只是告诉编译器该变量已经存在,此处通过编译,而不会开辟内存空间。
变量的使用就是对变量的读(取值)写(赋值)操作,变量的使用不会再开辟内存空间,而只是使用操作内存空间。

变量的定义

变量的定义就是让变量存在,系统会给变量开辟内存空间。变量定义的格式:数据类型 变量名; 例如 int age;变量名的本质是空间内容的别名,当操作变量名时,实际上操作的是变量名代表的那块内存空间。变量名要遵守相关的命名规则,否则编译器会编译错误

  • 以字母、数值、下划线组成
  • 不能以数值开头
  • 不能是关键字,例如int ,float等等29个关键字

在定义变量时如果变量频繁使用时定义寄存器变量,可以在变量前面使用register关键字。
而某些场景下编译器会自动优化代码,如果不想编译器优化,在变量前面使用volatile关键字。

变量的初始化

变量的初始化就是在变量定义的时候赋值,在使用变量前建议给变量赋初始值,这样的程序更加安全。

#define _CRT_SECURE_NO_WARNINGS#include #include /*    变量的初始化@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//变量的初始化:变量定义时赋值int age = 29;//此处不是变量的初始化,因为定义的时候没有赋值int number;//这里只是赋值number = 10;system("pause");return 0;}

变量的声明

变量的声明只是告诉编译器该变量已经存在,此处通过编译,而不会开辟内存空间。

变量的声明分为自动识别和显示声明两种

变量声明之自动识别:变量使用之前先定义、初始化变量,编译器会自动识别‘

#define _CRT_SECURE_NO_WARNINGS#include #include /*变量的声明:自动识别@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//变量的定义和初始化// 编译器是从上往下编译int number = 10;//变量的使用//变量使用之前定义,编译器就会自动识别变量printf("number = %d", number);system("pause");return 0;}

变量声明之显示声明:告诉编译器该变量存在,后面使用到该变量时通过编译,显示声明使用extern关键字,但是显示声明不能给变量赋值,否则会出现重定义错误,例如extern int data;

#define _CRT_SECURE_NO_WARNINGS#include #include /*变量的显示声明@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version*///显示声明:告诉编译器该变量存在,后面使用到该变量时通过编译//显示声明时不能给变量赋值,否则会出现重定义错误extern int data;int main(int argc, char* argv[]){printf("data =%d", data);system("pause");return 0;}//定义变量dataint data = 100;

日常开发中使用变量都是首先定义、初始化后再使用变量。而不会使用显示声明

变量的使用

变量表示程序运行过程中可以被改变的量,变量时存在于内存中,变量需要定义后再使用。
变量定义的语法格式: 数据类型 变量名 =变量值;例如int age = 28; 此时表示定整数变量age,并初始化赋值为28,age占据4个字节的内存大小。变量初始化指的是变量定义时赋值。
变量的定义和和赋值还可以分开,其语法格式是 数据类型变量名; 变量名=变量值;例如int number; number=10;
定义变量时系统会在内存开辟内存空间,变量名只是这块内存空间的别名,操作变量名即可以操作对应的内存空间。并告知编译器使用变量时通过编译。
变量名必须以字母和下划线开头,不能以数字开头,不能使用关键字,关键字是被C语言赋予了特殊的含义,例如int,short,double,float等等29个关键字。可以包含数字。

#define _CRT_SECURE_NO_WARNINGS#include #include /*    变量的使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/20*/int main(int argc, char* argv[]){    //变量的写操作 //赋值就是将10写入number代表的内存区域    int number = 10;    //变量的读操作    //读取number代表的那块存储区域的值并输出到终端    printf("number = %d ", number);    //定义整数变量new_number    int new_number;    //读取number的值写入new_number变量代表的那块内存空间    new_number = number;    //读取new_number代表的那块内存空间的内容并输出到终端    printf("new_number = %d ", new_number);    // 变量的算术运算    //将new_number代表的空间内容10+20之后的结果赋值给new_number    //这里加法(+)的优先级高于赋值运算符(=),会先计算new_number+20的结果,再赋值给new_number    new_number = new_number + 20;    //因此new_number = 30    printf("new_number = %d ", new_number);system("pause");return 0;}

整型

整型常量

整型常量的三种进制形式

C语言的整数常量支持八进制,十进制和十六进制,不支持二进制,其中八进制的整数常量以0开头,例如0144,而十六进制的整数以0x或者0X开头,例如0x64,整数常量默认是十进制。

#define _CRT_SECURE_NO_WARNINGS#include #include /*    整数常量C语言的整数常量支持八进制,十进制和十六进制,不支持二进制@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//100默认是整数 //输出100的八进制常量表示方式// #表示打印进制的完整表示方式printf("100的八进制常量表示方式%#o",100);//输出100的十六进制常量表示方式printf("100的十六进制常量表示方式%#x",100);//输出100的十进制常量表示方式printf("100的十进制常量表示方式为%d",100);/****************十进制整数123转换为八进制和十六进制*****************///输出123的八进制// 123转换成八进制的结果173//手动计算时 首先将123用短除法转换为2进制的结果为1 111 011 ,然后三位二进制对应一位八进制,转换为八进制的结果为1 7 3printf("123的八进制常量表示方式为%o",123);//输出123的十六进制,首先将123用短除法转换为2进制的结果为111 1011 ,然后四位二进制位对应一位十六进制位,转换为八进制的结果是7bprintf("123的十六进制常量表示方式为%x", 123);system("pause");return 0;}

有符号整数常量和无符号整数常量

C语言中的整数常量默认是有符号类型的,而使用无符号常量需要在常量值后面添加u后缀

#define _CRT_SECURE_NO_WARNINGS#include #include /*有符号整数常量和无符号整数常量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/12*/int main(int argc, char* argv[]){//有符号常量printf("%d",1);//无符号常量 需要在常量值后面加上u后缀printf("%u",1u);system("pause");return 0;}

整型变量

整型变量按照不同的字节数量大小分为char,short,int,long,每个整数变量都有无符号的类型,默认是有符号的类型。

#define _CRT_SECURE_NO_WARNINGS#include #include /*整型的四种类型(char,short,int,long,long long)变量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version*/int main(int argc, char* argv[]){char ch = 97;printf("ch变量占据的字节数量是%d",ch);short st = 100;printf("st变量占据的字节数量是%d", st);printf("st = %hd",st);int intVal = 100;printf("intVal变量占据的字节数量是%d", intVal);printf("intVal = %d", intVal);long longVal = 100L;printf("longVal变量占据的字节数量是%d", longVal);printf("longVal = %d", longVal);long long longlongVal = 100LL;printf("longlongVal变量占据的字节数量是%d", longlongVal);printf("longlongVal = %d", longlongVal);system("pause");return 0;}

使用printf()函数按照不同的进制形式打印输出变量的值时,只是输出的形式改变,在内存中存储的数据并没有发生改变。

#define _CRT_SECURE_NO_WARNINGS#include #include /*整数变量的定义和输出@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){int number = 100;//打印十进制整数变量number的三种进制表示方式printf("number = %d ",number);//无论以几进制打印输出,不会影响原来的结果printf("number = %o ",number);printf("number = %x ",number);system("pause");return 0;}

在打印整数时可以使用格式符%d按照十进制有符号打印输出到终端和格式符%u按照十进制无符号整数打印输出到终端

#define _CRT_SECURE_NO_WARNINGS#include #include /*整数变量的定义和输出@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){char data = 0x81; // 补码 1000 0001//补码1000 0001 转反码 1111 11110 加1求原码 1111 1111 //因此输出结果 char = -127printf("data = %d ",data);//无符号整数// 1000 0010 换算成十进制结果为130// 无符号输出结果为udata=130unsigned char udata = 0x82;printf("udata = %u ", udata);/*理解格式符字符串%d和%u的区别*///定义一个十六进制的整数变量,并初始化值为0x83char value = 0x83;/*0x83 转换为二进制 1000 0011因为赋值时是16进制,因此1000 0011 此时是补码按照十进制有符号打印需要转换为原码1000 0011 转换为反码的结果是1111 11001111 1100转换为原码的结果是1111 11011111 1101 最高位是1 表示该数值是负数1111 1101 转换十进制的结果是-125按照十进制有符号打印的结果是-125*/printf("0x83按照十进制有符号打印的结果是%d",value);unsigned int val = 0xffffffff;/*0xffffffff 转换为二进制 1111 1111 1111 1111 1111 1111 1111 1111  因为赋值时是16进制,因此1111 1111 1111 1111 1111 1111 1111 1111    此时是补码按照十进制有符号打印 需要将1111 1111 1111 1111 1111 1111 1111 1111 转换成原码1111 1111 1111 1111 1111 1111 1111 1111 转换成反码 1000 0000 0000 0000 0000 0000 0000 0000 1000 0000 0000 0000 0000 0000 0000 0000 转换成补码的结果是1000 0000 0000 0000 0000 0000 0000 00011000 0000 0000 0000 0000 0000 0000 0001 输出的结果是-1因此 0xfffffffff按照十进制有符号打印的结果是-1%u把0xffffffff看出一个无符号数直接将0xffffffff转换成十进制输出即可 1111 1111 1111 1111 1111 1111 1111 1111 按照无符号打印的结果是4294967295*/printf("0xffffffff按照十进制有符号打印的结果是%d", val);printf("0xffffffff按照十进制无符号打印的结果是%u", val);system("pause");return 0;}

计算机内存存储数据的方式

原码、反码和补码

任何数据在计算机中是以补码的方式存储,而数据的表现形式有原码、反码和补码。
正数的原码,反码和补码都一致,而负数经历了原码->反码->补码的换算过程

  • 原码
    原码表示数据本身的二进制
    例如无符号数15以一个字节的原码表示为0000 1111
    有符号 分为正数和负数,最高位表示符号位。正数15 以一个字节的原码表示为 00001111,而负数-15以一个字节的原码表示为1000 1111
  • 反码
    无符号数 反码等于原码,以一个字节的无符号整数15为例,其原码为0000 1111,其反码也是0000 1111
    有符号数 正数反码等于原码,负数就是最高位不变,其他位取反,以-15为例,其原码为 1000 1111,反码表示为1111 0000
  • 补码
    无符号数 补码等于原码
    有符号数 正数补码等于原码,负数就是反码的最低位加1即可,以-15为例,原码为 1000 1111 ,反码表示为1111 0000,补码就是反码加1,其结果是1111 0001。

综上所述,无符号数以及有符号正数计算机存的是原码,因为补码等于原码。而有符号负数计算机存储的是补码,补码等于原码取反加1。

原码->反码->补码的演变过程(以signed char类型说明)

首先明确 原码的+0,+1和-0,-1表示方法
0的原码是0000 0000 ,1的原码是0000 0001
-0的原码是1000 0000, -1的原码是1000 0001

无符号正数,有符号正数的原码,反码和补码都是一样的

为什么有了原码还需要补码,这里以原码计算1-1,因为计算器内部只有加法器,因为1-1 等价于1+ -1,因此
0000 0001+ 1000 0001=1000 0010 转换成十进制 等于-2 ,证明使用原码存储负数,在参与运算时得到的确是错误的结果。
除此以外,使用原码表示0有两种表示方法:0000 0000 和1000 0000

因为原码的负数运算结果错误,而且不能正确的表示0,因此计算机行业的大佬们开始尝试使用反码来存储负数

首先明确 反码的+0,+1和-0,-1表示方法
0的原码是0000 0000,转换为反码是0000 0000 ,1的原码是0000 0001,反码是0000 0001
-0的原码是1000 0000,转换为反码是1111 1111, -1的原码是1000 0001,反码是1111 1110

使用反码计算 1+ -1 = 0000 0001+1111 1110=1111 1111 ,1111 1111刚好是-0的反码,虽然负数使用反码运算时,结果准确,但是0的表示方式依然还是有两种:0000 0000 和1111 1111。

综上所述 如果计算机使用反码存储负数,运算准确,但是0的反码表示方式还是有两种。

由于反码不能正确表示0的方式,计算机大佬们又开始想新的方式:补码来存储负数

首先明确 补码的+0,+1和-0,-1表示方法
0的原码是0000 0000,转换为反码是0000 0000,转换为补码是0000 0000 ,1的原码是0000 0001,反码是0000 0001,转换为补码是0000 0000
-0的原码是1000 0000,转换为反码是1111 1111,转换为补码为0000 0000, -1的原码是1000 0001,反码是1111 1110,转换为补码是1111 1111

使用补码计算 1+ -1= 0000 0001 + 1111 1111=0000 0000 转换为十进制的结果就是0,而且补码+0和-0的二进制表示方式都是0000 0000,因此补码即解决了负数运算时的结果正确性,又保证了0只有一种0000 0000的表示方式,

整数溢出的原理

在使用对应数据类型时不要超过它们的范围,如果超过了就会造成数据溢出错误,执行程序会得到一个错误的逻辑。

#define _CRT_SECURE_NO_WARNINGS#include #include /*    整数的越界@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//赋值时(修改变量的值) 赋的值是十进制,给的是原码,如果赋值给的是八进制或者十六进制,给的是补码//打印输出到终端(获取变量的值)十进制打印的是原码,十六进制或者八进制打印输出的是补码/*    数据溢出的内存原理129的原码表示方式为 1000 0001,但是number是有符号数,最高位为1,计算机认为这是一个负数的补码,因此需要转换从原码输出补码求原码首先需要经过补码求反码,然后再由反码求原码的过程补码求反码:符号位不变,其他位取反。1000 0001转换为反码的结果是1111 1110反码求原码:反码+1 ,1111 1110 +1=1111 11111111 1111 最高位是符号位,而111 1111 转换成十进制的结果是127,最终输出的结果就是-127*/char number = 127+2;printf("number = %d",number);system("pause");return 0;}

程序运行结果

406cdb0cc277d6be8cbdfbb82e3e29ac.png

整数赋值溢出的原因剖析

赋值时(修改变量的值) 赋的值是十进制,给的是原码,如果赋值给的是八进制或者十六进制,给的是补码
打印输出到终端(获取变量的值)十进制打印的是原码,十六进制或者八进制打印输出的是补码

129的原码表示方式为 1000 0001,但是number是有符号数,最高位为1,计算机认为这是一个负数的补码,因此需要转换从原码输出补码求原码首先需要经过补码求反码,然后再由反码求原码的过程

补码求反码:符号位不变,其他位取反。1000 0001转换为反码的结果是1111 1110
反码求原码:反码+1 ,1111 1110 +1=1111 1111

1111 1111 最高位是符号位,而111 1111 转换成十进制的结果是127,最终输出的结果就是-127

变量赋值以及printf()函数输出的原理

#define _CRT_SECURE_NO_WARNINGS#include #include /*变量赋值以及printf()函数输出的原理@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//赋值时(修改变量的值) 赋的值是十进制,给的是原码,如果赋值给的是八进制或者十六进制,给的是补码//打印输出到终端(获取变量的值)十进制打印的是原码,十六进制或者八进制打印输出的是补码/*0x82转换为二进制的结果是1000 0010  十六进制赋值,给的就是补码printf("ch = %d",ch);打印 表示的打印输出到终端(获取变量的值)十进制打印的是原码,因此需要将1000 0010转换为原码输出1000 0010转换为反码1111 11011111 1101转换为原码1111 11101111 1110  最高位是1,在计算机看来是一个负数 ,转换为十进制的结果是-126*/char ch = 0x82;printf("ch = %d", ch);/*//赋值时的值是十进制,因此给的是原码-123的二进制原码表示方式为1111 11011而printf("ch = %d", ch); 示的打印输出到终端(获取变量的值)十进制打印的是原码, 1111 11011转换为十进制的结果是-123因此打印输出为ch =-123*/ch = -123;printf("ch = %d", ch);/*//赋值时的值是十六进制,因此给的是补码0xffffffff的二进制补码表示为1111 1111 1111 1111 1111 1111 1111 1111而printf("num = %d",num); 示的打印输出到终端(获取变量的值)十进制打印的是原码,1111 1111 1111 1111 1111 1111 1111 1111 转换为反码 1000 0000 0000 0000 0000 0000 0000 0000反码  1000 0000 0000 0000 0000 0000 0000 0000 转换为原码的结果是1000 0000 0000 0000 0000 0000 0000 00011000 0000 0000 0000 0000 0000 0000 0001 最高位是负数,因此结果输出为-1*/int num = 0xffffffff;printf("num = %d", num);system("pause");return 0;}

读取键盘输入

之前在定义整数变量并初始化值时只能写死一个值,整数变量建议初始化时为0,这样可以避免许多不必要的错误出现。

为了让程序变得更加灵活,这里引入C语言标准库函数scanf()函数实现基于终端字符界面的人机交互,该函数声明在stido.h文件中。当然日常应用(例如淘宝、京东)都是基于UI界面实现人机交互,但是底层处理的逻辑是一样的。

scanf()函数的运行流程

当用户从键盘输入数据回车()后,系统会将数据传到标准输入(stdin)文件中,scanf()函数可以从标准输入中读取用户输入的数据,以回车()为读取结束的标记(空格也会作为结束标记),该函数的参数需要传递 提取数据格式和变量地址两个参数,提取数据格式指的就是用户输入的数据类型,例如整数、小数等等,变量地址就是&变量名,&表示地址符号,变量名只能代表空间的内容,通过&变量名获取变量对应存储空间存储的值。需要注意的是scanf()函数是阻塞式的,如果用户不输入数据并且回车(回车等价于),那么程序会一直处于阻塞状态,直到用户输入数据按回车后程序继续往下执行。

#define _CRT_SECURE_NO_WARNINGS#include #include /*   使用scanf函数读取用户从键盘输入的整数数据@author liuguanglei ittimelinedotnet@gmail.com@wechat 18601767221@website ittimeline.net@version 2021/11/21*/int main(int argc, char* argv[]){//变量初始化时如果类型为整数,推荐初始化为0int age = 0;printf("请输入你的年龄(按回车键结束)");//此时程序会进入阻塞状态//当用户输入数据并回车之后先到达标准输入缓冲区//scanf函数负责从标准缓冲区拿整数,此函数是阻塞的,即等到用户输入数据并回车之后才会往下执行//%d表示提取键盘输入的数字,直到遇到为止,遇到空格也会结束//变量名仅仅代表变量的内容,如果想要获取变量的起始地址,需要使用&变量名scanf("%d", &age);printf("你的年龄是%d", age);system("pause");return 0;}

程序运行结果

4567ec4fbec2387fc64638170bea75a8.png

字符型

字符型常量

在日常生活中,字符串的信息含量能比数字表现更多的含义,例如网络传输都是以字符串的方式传输的,而字符串是由一系列字符组成的
C语言中一对单引号''包含的单个字符就是字符常量,可以用于表示一个字符。
字符占据1字节的内存空间,使用char声明字符类型的变量,字符变量本质存储的是字符的ASCII(American Standard Code for Information Interchange)值,ASCII编码规定了字符对应的整数。

b0e6f5e8c91335a090b60ee3f668f407.png
  • 字符'a'对应的ASCII编码是97
  • 字符'A'对应的ASC||编码是65
  • 字符'0'对应的ASCII编码是48
  • 转义字符'0'对应的ASCII编码是0
#define _CRT_SECURE_NO_WARNINGS#include #include /*字符常量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//打印字符printf("%c",'a');//字符在计算机内部使用ASCII值存储,其中'a'存储的是97//打印字符a的数字表示printf("a字符对应的ASCII编码是%d", 'a');//'A'对应的ASCII编码是65printf("A字符对应的ASCII编码是%d", 'A');//'0'对应的ASCII编码是48printf("A字符对应的ASCII编码是%d", 'A');system("pause");return 0;}

程序运行结果

5b99ba23ecaa5ac615ae7dcbf776d792.png

字符型变量

由于计算机底层存储字符时存储的是ASCII编码,因此可以通过printf()函数和格式符%c和%d实现字符与ASCII编码值相互转换输出

#define _CRT_SECURE_NO_WARNINGS#include #include /*字符变量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){char ch = 'a';printf("字符a的ASCII值时是%d",ch);ch = 97;printf("ASCII值97对应的字符是%c", ch);system("pause");return 0;}

计算机内部在存储字符时都是存储的ASCII编码对应的数值,既然是数值就可以进行算术运算,即加减乘除,因此字符也可以进行算术运算,char是int的最小单位(即1个字节)

#define _CRT_SECURE_NO_WARNINGS#include #include /*字符与算术运算@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version  2020/11/21*/int main(int argc, char* argv[]){char ch = 'a';ch = ch + 1;// ch = 98printf("ch = %d", ch);// ch = bprintf("ch = %c", ch);system("pause");return 0;}

字符的大小写转换
通过ASCII表得知

  • 小写字母转大写字母 -32 ,例如小写字母a的ASCII值是97,97-32=65,而65刚好是大写字母A的ASCII值
  • 大写字母转小写字母 +32,例如大写字母A的ASCII值是65,65+32=97,而97刚好是小写字a的ASCII值
#define _CRT_SECURE_NO_WARNINGS#include #include /*    字符的大小写转换@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version  2020/11/21*/int main(int argc, char* argv[]){    // 小写字母转大写字母 -32 ,例如小写字母a的ASCII值是97,97-32=65,而65刚好是大写字母A的ASCII值    char lower_case_a = 'a';    char upper_case_A = lower_case_a - 32;    printf("upper_case_A = %c ", upper_case_A);    //另外一种写法    upper_case_A = lower_case_a - ('a' - 'A');    printf("upper_case_A = %c ", upper_case_A);    // 大写字母转小写字母 +32,例如大写字母A的ASCII值是65,65+32=97,而97刚好是小写字a的ASCII值    char upper_case_B = 'B';    char lower_case_b = upper_case_B + 32;    printf("lower_case_b = %c ", lower_case_b);system("pause");return 0;}

字符'8' 转换为整数8

#define _CRT_SECURE_NO_WARNINGS#include #include /*字符和整数的相互转换@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version  2020/11/21*/int main(int argc, char* argv[]){char ch = '8';int number = ch - '0';printf("number =%d ",number);system("pause");return 0;}

使用scanf函数读取单个字符

#define _CRT_SECURE_NO_WARNINGS#include #include /*使用scanf()函数读取单个字符@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){char ch = 0;printf("请输入一个字符(按回车结束)");scanf("%c",&ch);printf("你输入的字符是%c",ch);system("pause");return 0;}

scanf读取单个字符

4e640ef07e7d87eb94360b43d7834ca8.png

常用的转义字符

转义字符指的是 一些无法直接显示的字符,转义字符使用'*'表示,常用的转义字符

  • 'a'表示发声音
  • 表示tab
  • 表示换行
  • 表示光标回到行首
  • %%表示%
  • 表示
#define _CRT_SECURE_NO_WARNINGS#include #include /*转义字符的使用@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){    // a发声音    printf("%c", 'a');    // 表示换行    printf("###%c###", '');    // 表示tab    printf("###%c###", '');    //光标回到行首 只会输出456,因为让光标回到了行首,之前输出的123被覆盖了    printf("123%c456", '');     // 转义字符会用于路径转义  输出结果是D:workspacecittimelinedotnetvs2019c-core    printf("D:workspacecittimelinedotnetvs2019c-core");    // %%表示%    printf("%%90");    //输出90%    //前面的%%表示% 后面的%d表示输出整数    printf("%%%d", 90);system("pause");return 0;}

浮点型

浮点型常量

浮点型就是数学意义上的小数,C语言提供了float和double两种类型的浮点数常量,其中f后缀的表示float,浮点数默认是double类型。
浮点数常量除了小数外还可以使用科学计数法表示,例如3.4e5表示3.4*10^5

#define _CRT_SECURE_NO_WARNINGS#include #include /*浮点型常量与printf()@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){// %f 默认输出小数点后6位数printf("%f",3.14f);//%.2f表示保留2位输出// 3.14 默认是double类型printf("%.2f",3.14);  //浮点数除了使用小数表示外,还可以使用科学计数法来表示printf("%.2lf", 3.4e5);system("pause");return 0;}

浮点型变量

浮点类型的变量按照精度的不同分为float和double,其中float占据4个字节,,double占据8个字节。因为float只能精确到7个有效数字,而double可以精确到15个有效数字,因此日常开发中使用double来声明和使用浮点型的变量。

##define _CRT_SECURE_NO_WARNINGS#include #include /*    浮点类型变量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){//浮点数是不精确的volatile float flt = 3.1415926535898f;register double dbl = 3.1415926535898;//float 保证7位有效数字 ,即整数部分+小数部分7位printf("flt = %.8f",flt);//double 保证15位有效数字 ,即整数部分+小数部分15位printf("dbl = %.13lf", dbl);//因为double的精度更高,因此通常使用double声明和使用double类型的变量//浮点数除了使用小数表示外,还可以使用科学计数法来表示printf("%.2lf", 3.4e5);double exponent = 3.4e5;printf("小数点的形式输出3.4e5---------->%.2lf",exponent);printf("科学计数法的形式输出3.4e5---------->%e",exponent);return 0;}

字符串

字符串常量

C语言中使用一对双引号("")包含的内容是字符串,字符串就是由一系列字符组成的,同时以0字符作为结束标记。
转义字符'0'的ASCII是0,因此'0'和0是等价的,而字符'0'的ASCII编码是48

#define _CRT_SECURE_NO_WARNINGS#include #include /*字符串常量@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version*/int main(int argc, char* argv[]){//字符串是以"" 包含的内容// 字符串常量是以'0'结尾,作为字符串的结束标记,'0'的ASCII值是0printf("我的名字是%s","刘光磊");system("pause");return 0;}

字符串的格式化输出

格式化打印整数和浮点数

#define _CRT_SECURE_NO_WARNINGS#include #include /*字符串的格式化输出@author liuguanglei 18601767221@163.com@wechat 18601767221@website ittimeline.net@version 2020/11/21*/int main(int argc, char* argv[]){int number = 19;//打印整数19占5个字符,不足补空格printf("number = %5d ",number);//打印整数19占5个字符,不足补00printf("number = %05d ",number);double dbl = 3.1415;printf("dbl = %.4lf",dbl);//小数点后保留四位,字符宽度为10printf("dbl = %10.4lf",dbl);system("pause");return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值