导图社区 C加加数据类型详解
这是一篇关于C++一级考试知识点的思维导图,包括基础代码、变量、数学运算和循环四部分内容,内容详细,考试复习必备。
编辑于2021-08-08 18:30:40"重构人生的12条黄金法则:从拒绝平庸到活出独特自我首先打破认知枷锁,用‘反愿景’明确人生底线绝对自由等于混乱,平庸是最昂贵的代价接着用高标准重塑身份,让卓越成为习惯能力提升要聚焦实战,以生活为项目炼就深度通才每日推进关键任务,用持续创造撬动自由保持创业心态,把不确定性当跳板,用自我实验突破极限记住:所有努力只为活出不可复制的生命剧本,包括接纳过程中的重大失误。
在职场沟通场景中,日报的本质是「工作价值的结构化呈现工具」。 许多人之所以会陷入写作困境,核心矛盾并非表达能力不足,而是日常工作缺乏目标导向的思维框架与成果沉淀的行为模式。 这里我将尝试以麦肯锡式思维逻辑为底层框架,拆解从工作规划到日报输出的全流程方法论,帮助职场人建立「思考有模型、执行有标准、呈现有效率」的工作体系。
C 类的封装方法:类的定义,类的构造函数,成员函数,重载构造函数,析构函数,静态成员等详细案例解析和理论罗列。
社区模板帮助中心,点此进入>>
"重构人生的12条黄金法则:从拒绝平庸到活出独特自我首先打破认知枷锁,用‘反愿景’明确人生底线绝对自由等于混乱,平庸是最昂贵的代价接着用高标准重塑身份,让卓越成为习惯能力提升要聚焦实战,以生活为项目炼就深度通才每日推进关键任务,用持续创造撬动自由保持创业心态,把不确定性当跳板,用自我实验突破极限记住:所有努力只为活出不可复制的生命剧本,包括接纳过程中的重大失误。
在职场沟通场景中,日报的本质是「工作价值的结构化呈现工具」。 许多人之所以会陷入写作困境,核心矛盾并非表达能力不足,而是日常工作缺乏目标导向的思维框架与成果沉淀的行为模式。 这里我将尝试以麦肯锡式思维逻辑为底层框架,拆解从工作规划到日报输出的全流程方法论,帮助职场人建立「思考有模型、执行有标准、呈现有效率」的工作体系。
C 类的封装方法:类的定义,类的构造函数,成员函数,重载构造函数,析构函数,静态成员等详细案例解析和理论罗列。
C++数据类型详解
常量和变量的概念
常量
又称为字面常量
之所以称为“字面”,是因为只能用其值来指代,称之为“常量”,是因为其值不能被改变。例如123这个常量,其值只能是123,而不能被改成456。
字面常量没有名字,要使用一个字面常量就只能通过常量的值。
作用
初始化变量
给变量赋值
参与表达式计算
类型
类型由其值决定
处理方法
不同类型的常量接受的处理方法不同
作用域
后面讲
定义方法
const 类型 常量名 = 值;
#define 常量名 值
变量
其值可以改变
用名称标记的一块内存
可以存储数据
有名称
要符合命名规则
和C语言标识符的命名标准相同
变量只能由字母、数字以及下划线组成
必须以字母或者下划线开头
区分大小写
容易记,意思明,目的强
是一种标识符
标识符是对程序中实体名称的统称
常量
枚举常量
变量
函数
类
结构体
模板
关键字不能做标识符
关键字就是C++的保留字,用户不能更改其含义,只能按照规定的用途使用
主函数名main也是关键字,表示函数返回的return也是关键字。关键字不能用做标识符,否则会引起编译错误。
与C的区别
与C语言不同,C++可以随时定义所需的变量,而不必放在函数的开始处。定义变量时,先指定变量的类型,再给出变量名,并以分号“;”
类型 变量名;
以分号结束变量的定义,表示变量的定义也是一个语句。其中的“类型”就是这个变量所能处理的数据的类型。为了表示各种数据类型,C++语言设立了多个关键字,或者说是类型名,
类型
整型
short
123
short 型的字面常量没有后缀,其形式同 int 型的字面常量一致,编译器会根据需要将这个字面常量解释为short型或者int型。
int
24
03C
0xF8
0XF8
如果一个字面常量在程序中写成上述形式,则编译器会自动将其当做整型数对待。在整型字面常量前面加一个“0”,该值将被解释成一个八进制数,而在前面加一个“0x”或“0X”,则会使一个整型字面常量被解释成十六进制数。
long
456L
long long int
123LL
特殊类型关键字
定义的原因
C++标准规定short的大小是半个机器字,int的大小是一个机器字,而long的大小是一到两个机器字。这就存在一个程序移植方面的问题:如果两个计算机的机器字大小不一样(比如一个是32位,而另一个是64位),则在定义、初始化、赋值时对整型变量的操作就不一样,从而导致这两台计算机的程序不可以互相移植
解决方法
C++标准引入了一些特殊类型关键字用来表示确定大小的整型数。如__int8,__int16,__int32和__int64分别表示8位、16位、32位和64位的整数,使用这些类型定义变量的语法同int型一样
__int8
__int16
__int32
__int64
有符号和无符号
signed
一般省略
unsigned
无符号整型字面常量可以在一般字面常量后面加上后缀“u”或“U”来表示
unsigned int x = 123u
unsigned int = 123LU
浮点型
float
1.23f
1.23F
单精度浮点型
double
4.56
7.
没有后缀的浮点型字面常量是double 型的
long double
8.9L
长精度浮点数
浮点型字面常量的后缀“f”、“F”、“l”、“L”只能用在十进制形式中。
浮点型字面常量可以被写成普通的十进制形式,或者用科学计数法表示。科学计数法是指数值中带有指数的表示方式
字符型
char
表示单个字符
'a'
表示小整数
'1'
字符型数据和整型数有一定的转换关系。计算机不能直接存储字符,所以所有字符都是用数字编码来表示和处理的。
'a'
97
'A'
65
'+'
43
wchar_t
例如: L'a'
宽字符型常量
其字面常量是在char型字符前加上前缀“L”
宽字符。一个宽字符在32位计算机中一般占2个字节。
所谓宽字符,指的是用两个字节表示的字符。C++中使用宽字符是为了支持Unicode。
其目的是用同一种编码方式处理世界上所有语言中的字符,这就是Unicode编码。
只需知道C++的wchar_t类型是用来表示和处理Unicode字符的即可。
示例
wchar_t w; w = L'Z'; wchar_t v = L'V';
unsigned char
无符号字符型
除了包括ASCII码上的所有字符外,还包括一个扩展ASCII码表上的所有字符
目前键盘上无法输出的扩展ASCII码表上的字符可以通过字符与整数的关系来初始化或赋值无符号字符型变量
#include <iostream> using namespace std; int main(int argc, char** argv) { unsigned char c = 128; cout << c << endl; return 0; }
转义字符
在C++中有些字符不能直接表示,只能通过特殊的方法表示
对于这一类字符可以用在某个字符前加一个反斜杠来表示
反斜杠的含义是改变后面字符的意义,用来表示另外的字符
'\n'与'\r'的区别
换行符'\n'
换行只是将输出位置换到下一行,不改变输出的横坐标;
相当于std::endl
回车符'\r'
回车是回到行首,不改变输出的纵坐标。
有些有歧义的字符,也需要用 反斜杠开始的转义序列表示。
#include <iostream> using namespace std; int main(int argc, char** argv) { unsigned char c = 128; int a = 123456; char b[] = {1, 2, 3, 4, 5}; cout << a << "\n" << endl; cout << c << endl; cout << '\'' << endl; cout << '\x42' << endl; cout << '\123' << endl; return 0; }
123456 € ' B S
布尔型
bool
bool b; b = true; bool c = false;
用途
一个布尔型变量常用来表示某个条件是否成立
示例
int a_1 = 0; int b_1 = 0; cin >> a; cin >> b; bool flag = false; if (a_1 > b_1) { flag = true; cout << "a_1 > b_1"<< endl; } else { cout << "a_1 <= b_1" << endl; }
在程序中,布尔型变量可以看做整型变量。字面常量true可以当做整数1,false可以当做整数0,
当其他类型的数据转换为布尔型数据时,只要是非0的数据都将转换为true,而0则转换为false
派生类型
结构体
共用体
枚举体
用户自定义类型
生命周期
后面讲
变量的定义、初始化、赋值
定义
未定义
所谓未定义,就是C++标准并没有规定具体的数值,而是由编译器根据需要自行指定。但这个值是没有意义的,开发者在编写程序时不能依赖这个值。
初始化
变量的初始化可以在定义变量时进行,只需在变量名后加上等号“=”和一个初始化值即可。这个初始化值可以是一个常量,也可以是一个变量。
类型变量名 =初始化值;
如果变量定义时没有初始化,则其值取决于编译器的实现。这样的值是没有意义的,所以使用未经初始化的变量比较危险
C++的语法允许在一个语句里定义多个变量,也允许在一个语句里初始化多个变量
不建议这样搞哈
C++也支持链式初始化,即用等号“=”连接多个变量名,并在最后一个变量名后面加上一个等号和一个初始化值,这样就可以将全部变量都初始化成一个值,其语法如下:
int a = b = c = 123
同样不建议
链式初始化的过程是从右往左的,即先定义最右面的变量,并将其初始化为等号右边的值,然后依次向左定义并初始化各个变量。
赋值
既然是变量,则在定义之后,其值就是可以修改的。修改变量值的过程就是赋值,其语法同初始化语法类似,只是没有类型关键字
变量 =值;
与初始化的不同
初始化是给未曾使用的变量设定一个值,而赋值则是修改已经在使用的变量的值;初始化只发生一次,即在变量定义时,而赋值则可以发生多次。
为变量赋值也支持链式赋值,即为一系列的变量赋以同样的值。其语法同变量的链式初始化类似,只是没有开始的类型关键字
链式赋值的顺序同链式初始化的顺序相同,都是从右向左的,即先给最右面的变量赋值,然后依次向左给每个变量赋值。
变量的值,无论是初始化的值,还是后来赋的值,其类型都应当与变量的类型相同,或者符合转换规则。我们可以将整数转换为浮点型数,浮点型数也可以转换为整数(存在精度损失)
一个整型变量可以用一个字符初始化,也可以用一个字符赋值;反之,一个字符变量也可以用一个整数进行初始化和赋值
在用整数表示一个字符时,注意不要超过其取值范围。ASCII 码表总共有 128 个字符,所以与字符数据对应的整数也就有128个,其取值范围是0~127。
变量与内存
变量就是一段内存。既然是内存,就有地址、大小等方面的属性
变量的地址
计算机的内存按照字节进行编码的,内存中一个字节的编码就是这个字节的地址
OS可以按照内存地址对内存进行存取操作
在C++中定义一个变量就是声明占用一块内存,变量名就指向这块内存的首地址
在C++程序中定义一个变量,即表示占用一块儿内存。变量名代表这块儿内存的首地址
变量的字节长度
变量是用来存储数据的,不同类型的数据对内存大小的要求不一样
数据占用的内存数量称为数据的大小,通常用机器字来衡量
机器字
一个机器字即计算机在一个时钟周期内,能够从内存中读取的数据大小(机器字),在32位机器中是2个字节(32位),在64位机器中就是4个字节(64位)。
C++标准规定内建的数据类型大小
int
1个机器字
short
半个机器字
long
1/2个机器字
对于某个确定版本的编译器和某种计算机处理器,这些尺寸都是固定的。
float
一个机器字
double
两个机器字
long double
3/4个机器字
对于某个确定版本的编译器和某种计算机处理器,这些尺寸都是固定的。
虽然数据的尺寸是用机器字来衡量的,但通常在表述数据大小时却是以字节为单位的。在32位机器中,一个机器字是4个字节,所以,在32位平台中常用的int型是4个字节,short型是2个字节,long型一般也是4个字节。
变量的类型则决定了这块儿内存的长度。
计算数据的字节长度
sizeof()
sizeof(类型名)
sizeof(变量名)
sizeof(常量)
sizeof运算的结果是一个size_t型的数据。size_t是一种内建数据类型的别名
关于类型别名以及格式化输出问题后面展开
示例
#include <iostream> using namespace std; int main(int argc, char** argv) { short a0 = 0; int a1 = 1; long a2 = 2L; char c = 'c'; float d0 = 1.23F; double e0 = 12.35; bool b = true; // 计算并输出各种数据类型 cout << "short: " << sizeof(short) <<'\t' << sizeof(a0) << endl; cout << "int: " << sizeof(int) << '\t' << sizeof(a1) << endl; cout << "long: " << sizeof(long) << '\t' << sizeof 2L << endl; cout << "char: " << sizeof(char) << '\t' << sizeof(c) << endl; cout << "float: " << sizeof(float) << '\t' << sizeof(d0) << endl; cout << "double:" << sizeof(double) << '\t' << sizeof(e0) << endl; cout << "bool: " << sizeof(bool) << '\t' << sizeof(b) << endl; // cout << sizeof int << endl; 不使用括号的形式不能用于类型 return 0; }
short: 2 2 int: 4 4 long: 4 4 char: 1 1 float: 4 4 double:8 8 bool: 1 1
变量的取值范围
变量的类型决定了可取值的类型,而类型的字节长度则决定了变量可取值的范围。如字符型变量只占一个字节,它的值可以是ASCII和扩展ASCII字符集中的256个字符和符号。
结构体
struct
其后是结构体名称,然后是由两个花括号包围的结构体。花括号中是组成结构体的各种成员,可以是数据,也可以是函数。每个成员用分号“;”作为结尾。定义结构体格式如下:
struct 标识符 { 成员列表 }
struct someStruct { float a; int b; };
结构体定义最后的花括号后面必须带有一个分号,表示定义的结束。
由于结构体也是一种数据类型,所以也可以用来定义变量,其方法和定义普通变量的方法一样。例如定义一个SomeStruct结构体的变量:
someStruct s;
为了访问结构体变量中的成员,可以使用运算符“.”,
s.a = 10
上面是对结构体变量s的成员a进行赋值的操作。结构体类型本身不占用任何内存空间,只有结构体变量才占用内存空间,其占用的内存空间大小是各个数据成员类型大小之和。不过各种编译器出于效率的考虑,往往会对结构体变量进行内存对齐操作,从而使得结构体变量所占内存大小往往大于各个数据成员类型大小的和。
这就是访问内存问题的时候要注意的了
共用体
与结构体不同,共用体的数据成员存储时共享存储空间。
共用体在有的书中也被称为联合体类
其成员变量共享内存,所以修改a就会影响到b
union
union 标识符 { 成员表 }
union someUnion { int a; char b; float c; };
someUnion a;
对于共用体类型数据,其各个数据成员占用的内存是共享的,修改一个成员,就等于修改其他成员
示例
union someUnion { int a; int b = 456; int c ; }; someUnion x; x.a = 123; cout << x.b << x.c << endl;
输出结果
123123
warning: [Warning] non-static data member initializers only available with -std=c++11 or -std=gnu++11
解决方法
To make it C++98 compatible, you need to initialize non-static class constants outside of the class declaration.
union someUnion { int a; int b; int c; }; someUnion x; x.a = 123; cout << x.b << x.c << endl;
枚举体
如果要使变量只能使用有限的几个值,则应当使用枚举体。
摸球实验算法
之所以叫枚举体,就是因为在定义枚举体类型时,需要将所有可能的值一一列举出来。
enum
enum Day { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; Day day = Tue; cout << day << endl;
结果:1
其中day是一个枚举体Day类型的变量,其可能的取值就是定义Day时列举的7个值,在这里就是Tue。
虽然枚举体的值是由一些字符组成的,但这些值却可以当成整型数使用。如没有特别指明,则枚举体中的值就是从0开始的整数。例如在Day中,Mon对应的整数值是0,Tue对应的整数值是1,依此类推。
定义枚举体时所列举的各个标识符代表的是一系列常量,在程序中只能当做常量使用,而不能像变量一样为其赋值。
enum Day { Mon=1, Tue, Wed, Thu, Fri, Sat, Sun }; Day day = Tue; cout << day << endl;
结果为2
如上定义后Tue的值就是2,Wed值是3,依此类推。
使用宏替换字面常量
字面常量,如123,'a'等,虽然简单、直接,但使用起来并不方便。由于没有标识符,所以后来的人在阅读程序时就难以知道其由来。
double radius = 1.2; // 圆的半径 double perimeter = radius * 2 * 3.1415926; // 圆的周长 double area = 3.1415926 * radius * radius; // 圆的面积 double perigonRadian = 2 * 3.1415926; // 圆角的弧度 double rightRadian = 0.25 * 3.1415927; // 直角的弧度
直接使用字面常量不容易理解。例如在程序中直接使用3.14159265,由于这只是个数值,其本身不能自我说明,除程序员自己,别人难以知道这就是圆周率。字面常量容易写错。
在上面的代码中就是如此,第5行的圆周率跟前面使用的圆周率都不同。虽然都是真实圆周率的近似值,单独使用都没错,但在一个程序中应当保持一致,而直接使用字面常量难以保证这一点
如果程序中有多处使用同一个字面常量,那么当程序逻辑发生改变需要修改这个字面常量时就很麻烦,需要手动修改所有用到的地方。例如上述程序,如果实际计算时发现圆周率的精度不够,要改成3.141592653589才合乎要求,则需要查找所有用到原有圆周率的地方,并逐个进行修改,非常烦琐。
宏是一个预编译指令
语法
#define 宏名 宏的内容
这里不用分号结尾
上述语法称为宏定义。有了这个宏定义之后,源代码中的“宏的内容”就可以用“宏名”替换。例如,在上述那个圆周率的例子中,
#define PI 3.14159265 double radius = 1.2; // 圆的半径 double perimeter = radius * 2 * PI; // 圆的周长 double area = PI * radius * radius; // 圆的面积 double perigonRadian = 2 * PI; // 圆角的弧度 double rightRadian = 0.25 * PI; // 直角的弧度
宏的好处
宏比字面常量好理解。字面常量只有结合其使用情况才能明确其含义。而定义良好的宏,其本身的名字就可以表明其含义。
字面常量如果写错,则代表的是另外的常量,编译器不会报错。而宏名如果写错,编译就不会通过,程序的开发者就可以按照编译器的提示进行修改。
使用宏的程序比仅使用字面常量的程序容易修改。例如要提高圆周率的精度,只要在定义宏的语句中进行修改即可,以后代码中使用的PI都会是修改后的值。
注意
源代码中的宏,在编译之前由预处理器进行宏展开。所谓宏展开,就是将源代码中所有的“宏名”用“宏的内容”进行替换,其效果就如同直接书写“宏的内容”一样。宏展开时,预编译器不会对宏的内容进行任何检查,而是忠实地执行文本替换工作。例如,即便将宏 PI 定义成 3.14abc15926也是合法的,但在编译时会报错。
使用const定义常量
尽管宏(#define)的使用非常方便,但宏只是进行文本替换,而替换的内容没有任何限定。这样做虽然灵活,也非常危险。为此,C++引入了另外一种更好的定义常量的方法——const常量
语法
const 类型 常量名 = 初始化值
上面的语法类似于变量的定义,只是在前面加上了关键字 const。const 是限定符,表明其后定义的数据是一个常量。const常量在定义时必须进行初始化,因为一个常量定义后,其值是不能修改的。
const常量最大的优点是其定义中规定了常量的类型,因此,编译器可以根据其类型来使用。现在用const常量来修改前面那个圆周率的例子:
const double pi = 3.14159265; double radius = 1.2; // 圆的半径 double perimeter = radius * 2 * pi; // 圆的周长 double area = PI * radius * radius; // 圆的面积 double perigonRadian = 2 * pi; // 圆角的弧度 double rightRadian = 0.25 * pi; // 直角的弧度
其中常量 pi 的定义已经指定了其类型是 double,这样在初始化时 pi 能够接受的值就只能是double型的数据。
综合示例
#include<iostream> #include<cstdlib> using namespace std; struct Triangle { double a; double b; double c; }; int main(int argc, char** argv) { cout << "__三角形的计算和表示__" << endl; Triangle t; cout << "依次输入三角形的边长: "<< endl; cin >> t.a; cin >> t.b; cin >> t.c; double max = t.a > t.b ? t.a : t.b; // 求两边中的最大值 double x = t.a + t.b - max; // 求两边中的较小值 double z = max > t.c ? max : t.c; // 求三边中的最大值 double y = t.a + t.b + t.c - x - z; // 求第三边 if (z <=0 || z >= x + y) // 判断三角形的合法性 { cout << "输出的边长不能组成三角形" << endl; cout << endl; return 0; } if (z * z == x * x + y * y) { cout << "直角" << endl; } else if( z * z < x * x + y * y) { cout << "锐角" << endl; } else { cout << "钝角" << endl; } cout << endl; return 0; }