QT Creator中C++工程创建
中文乱码问题:QT是mini gnu for windows,mini gnu用utf8编码,但windows不是,因此会中文乱码。通过 工具 -> 选项开始设置。设置之后需要新建工程,对当前工程无效
C++基础
基础知识
Hello World程序
# include <iostream> //头文件包含,<>是系统头文件,标准输入输出流
//使用命名空间std
//如果不加这句,无法直接使用cout,需要写成std::cout,表示cout来自std
using namespace std;
int main(int argc, char *argv[])
{
// cout定向输出,endl换行,可以不换
cout << "Hello World!" << endl;
return 0;
}
变量
以int为例,int a=100,则系统会开辟一个4字节的空间。a是变量名,对变量名的操作等价于对空间等操作
void data; //报错,void不知道类型,系统不知道为data开辟多大的空间
变量的初始化
只有在定义变量
的时候,给变量赋值是初始化
int num = 10; //初始化
int num;
num = 10; //不是初始化,而是赋值
普通局部变量,如果不初始化,它的值不确定
全局变量(函数外定义的变量),如果不初始化,值为0
变量的声明 extern
变量的定义:创建变量名,开辟空间
变量的声明:对变量类型和名称事先说明,不会为变量开创空间
变量的使用:对已经存在的变量的读写
extern int data; //提前:变量声明。在需要先使用后定义的变量时,需要用extern关键字提前声明,表示外部可用,表示全局变量
void test{
cout<<"data="<<data<<endl; //先使用
}
int data = 0; //后定义;注意这一句应当放在函数外部
这种一般用于跨文件编程
键盘输入cin
/* 键盘获取最大值,并求最大值 */
// cin会跳过其实的空格和回车
int num1 = 0;
int num2 = 0;
cin>>num1>>num2; //输入两个值
if (num1>num2) cout<<num1<<endl;
else cout<<num2<<endl;
数据类型
整数型
如int
字符型
1. 字符变量
ch = 'x'; //从存储上讲,存储的是ASCII码值,120
cout<<(int)'x'<<endl; //输出ASCII值
//关于字符的初始化,可以初始化为'\0'
char c = '\0';
字符案例——大小写转换
char ch = 'a';
ch = ch-('a'-'A'); //小写转大写,也可以直接写成ch = ch-32
char ch = 'A';
ch = ch+('a'-'A'); //大写转小写,也可以直接写成ch = ch+32
2. 字符串
'a’是字符常量,只占一个字节
"a"是字符串常量,占2个字节,因为字符串会自动添加 ‘\0’ 作为结尾
实数型(浮点数)
浮点数能够表示带小数的类型
计算机将这样的值分为两部分存储,一部分表示值,另一部分用于对值进行放大或缩小。如34.1245可以看成是0.341245(基准值)和100(缩放因子)。
C++内部表示浮点数的方法与此相同,只不过它基于的是二进制,因此缩放因子是2的幂,不是10的幂。
实数型分为:单精度浮点数(float 4字节)和双精度浮点数(double 8字节)
1. 实型常量
不以f结尾的实型常量为double类型,如3.14
以f结尾的实型常量为float类型,如3.14f
指数形式:3.14e3表示3140
2. 实型变量
float f = 0.0f; //末尾必须加f
double d = 0.0; //末尾不用加标识
有符号数和无符号数
有符号数
数据二进制
的最高位为符号位,其他位为数据位
最高位为1,表示负数
最高位为0,表示正数
因此对于1字节,有8 bit,也就是有7位可表示数据位,因此
最大值表示为0b01111111,代表127 (首位不计入计算)
最小值表示为0b11111111,代表-127
注意:如果这样算,那么1字节的范围为-127 ~ 127
但是由于0b10000000和0b00000000分别表示将 -0 和 +0,因此将 -0 作为 -128,所以规定的1字节范围为-128~127
cout<<bitset<8>(-128)<<endl; //输出:10000000
无符号数
没有符号位,因此所有二进制位都是数据位,以1字节为例
00000000 ~ 11111111 表示范围为 0~255
int num; //默认为有符号,相当于signed int num;
unsigned int num; //无符号数,不能省略unsigned
进制
二进制、八进制、十六进制
- 二进制
//cout需要使用bitset<位数>(数值),位数一般是8,16,32
cout<<0b00001010<<endl; //以十进制输出,C++不直接支持二进制
cout<<bitset<8>(0b00001010)<<endl; //需要引入<bitset>头文件
- 八进制
cout<<oct<<0123<<endl; //使用oct输出八进制
- 十六进制
cout<<hex<<0xab<<endl; //使用hex输出十六进制
进制转换
- 十进制转其他进制
短除法:用十进制依次除以进制n,得到的余数反向排列
- 其他进制转十进制
位次幂:……xn2+yn1+zn0
- 二进制转八进制
从右往左:每3位二进制对应1位八进制
- 二进制转十六进制
从右往左:每4位二进制对应1位十六进制
- 八进制转二进制
每1位八进制对应3位二进制
- 十六进制转二进制
每1位十六进制对应4位二进制
- 八进制和十六进制之间的转换(没有直接方法)
利用二进制作为中间进制,进行八进制和十六进制的转换
原码、反码、补码
概述
原码:计算机中对数字的二进制定点表示方式
123:原码0111 1011
-
无符号数:补码 == 反码 == 原码
-
有符号数
正数:补码 == 反码 == 原码
负数:反码 == 原码符号位不变,其他位按位取反
补码 == 反码+1
-123原码:1111 1011
-123反码:1000 0100
-123补码:1000 0101
负数在计算机中以补码的方式存储
非负数在计算机中以原码的方式存储
二进制、八进制、十六进制以原码方式存储
补码的意义
- 统一了0的编码
+0补码:0000 0000
-0补码:0000 0000 //去掉最高位,仅保留位
- 将减法运算变成加法运算
例:没有补码:10-6
10: 0000 1010
-6: 1000 0110
--------------------
1001 0000 //将10的原码和-6的原码相加,结果为-16,不正确
有补码:10-6
10: 0000 1010
-6: 1111 1010
--------------------
0000 0100 //将10的原码和-6的补码相加,结果为6,正确
对数据的存
- 负数
负数以补码的方式存储在计算机中:查看 -10 在计算机中的存储方式
short data = -10; //short占2字节,即16 bit
cout<<bitset<16>(data)<<endl;
//输出:1111111111110110
-10的原码:1000 0000 0000 1010 (最高位在第16位)
-10的反码:1111 1111 1111 0101
-10的补码:1111 1111 1111 0110
- 二进制、八进制、十六进制
以原码存储,不再以最高位表示正负
short data = 0x8080; //以十六进制为例
cout<<data<<endl; //输出:-32640,但实际上Ox8080在十进制下为32896
cout<<bitset<16>(data)<<endl; //输出:1000000010000000,算上最高位转为十进制为32896
输出 -32640 是因为将其最高位作为负数计算了(实际上十六进制不能这样输出)。
-32640的补码:1000000010000000
-32640的反码:1000000001111111
-32640的原码:1111111110000000
对数据的取
无符号变量:输出内存的原样数据
有符号变量:(1)最高位为0,表示正数,内存原样输出
(2)最高位为1,表示负数,说明内存中存的是补码,于是倒退得到反码和原码,再输出负号和去掉最高位的原码值
/* 1. 无符号变量的取 */
unsigned short data = -10;
cout<<bitset<16>(data)<<endl; //输出:1111111111110110,为-10的补码形式
cout<<data<<endl; //输出:65526,将内存的进制原样输出,即计算机没有意识到这是补码,而将-10的补码转成了10进制
/* 2. 有符号变量的取 */
short data = -10;
cout<<bitset<16>(data)<<endl; //输出:1111111111110110,为-10的补码形式
cout<<data<<endl; //输出:-10,检测最高位,发现为1表示负数,于是执行补码-反码-原码的转换,再输出
有关二、八、十六进制的取,已在上面展示过了
关键字
const 修饰普通变量
const修饰data为只读变量,使得data只能被初始化,不能被赋值
const int data = 10; //初始化
data = 11; //报错!!
(1)当以常量初始化const修饰的变量时,只读变量data的值将事先存放在符号常量表
中,不会立即给data开辟空间
当对data取地址时,才会为其开辟空间
const int data = 10;
int *p = (int *)&data; //此时才会为data开辟空间,data将同时存在于符号常量表中和内存空间中
*p = 200; //修改p指向空间的值
cout<<*p<<endl; //输出:200
cout<<data<<endl; //输出:10
//data和p互不影响
(2)当以变量初始化const修饰的变量时,会立即分配存储空间,而不会放到符号常量表里
int a = 10;
const int data = a; //以变量初始化data
int *p = (int *)&data;
*p = 200; //修改p指向空间的值
cout<<*p<<endl; //输出:200
cout<<data<<endl; //输出:200
//data和p相互影响
两种情况下输出 p 和 &data,都会发现两者相同
(3)当以自定义类型变量(如结构体)初始化const修饰的变量时,也会立即分配存储空间
register修饰寄存器变量
如果变量被高频率使用,会自动将变量存储在寄存器中,目的:提高访问效率
如果想将变量直接放入寄存器中,可以加register修饰
一般的数据放在内存中。CPU处理速度快,但调用内存中的数据比较慢
寄存器在CPU中,放到寄存器中的数据调用起来更快
register int data = 0; //data放在寄存器中,而非内存中
尽量对寄存器变量取地址操作,如&data,放在寄存器中的变量没有地址。但是register修饰的变量只是尽量放在寄存器中,因为大小有限,放置失败的变量将仍被放入内存中
也就是没有register修饰的变量可能放入寄存器中;有register修饰的变量有很大可能放入寄存器中
volatile 关键字
强制访问内存
举例场景:以一氧化碳传感器为例,需要每n分钟收集一次浓度值。以data表示该值,变量存储在内存中
由于data被时常使用,系统会自动将data再复制到寄存器中,于是更新时的顺序是 传感器 -> 内存 -> 寄存器
可能出现内存中的数据被更新,但寄存器中的浓度未被更新。CPU读取寄存器中的变量没有获得及时数据,对于部分敏感数据可能造成严重影响。
volatile强制每次都从内存中读取,而不管该变量是否被复制到了寄存器中
volatile int data = 0; //对data的访问,必须从内存访问
typedef给已有的类型取别名
注意:不能创建新的类型
/* 1. 为int数据类型取别名 */
typedef int INT32; //INT32就是int类型的别名
INT32 data = 10; // 用别名定义变量
/* 2. 为 int arr[5]取别名 */
typedef int MYARRAY[5];
MYARRAY arr = {1,2,3,4,5}; // arr是一个5个数的数组
/* 3. 给int *取别名*/
typedef int *MYP;
MYP p; //p代表int *类型
转义字符
'\0' == ASCII为0
'\n' == 换行
'\t' == tab缩进符
'\r' == 回到行首符号;cout<<"##"<<'\r'<<"##"<<endl,最终只输出一个“##”,因为光标回到行首,被覆盖
'\a' == 发出警报
'\ddd' == 八进制转义,如'\123';每个d的范围为0-7
'\xhh' == 十六进制转义,两个h表示最多识别2位十六进制;如'\xab'
类型转换
自动类型转换
占用内存字节少的类型向占用内存大的内心的转换,可以自动转换。这可以保证精度不降低
由低到高转换:char, short -> signed int -> unsigned int -> long ->double;还有float -> double
(1)无符号和有符号参加运算,有符号转换成无符号
// -10+6,前者有符号,后者无符号,最终结果>0
int data1 = -10;
unsigned int data2 = 6;
if (data1+data2 > 0) cout<<">0"<<endl; //输出:>0
else cout<<"<=0"<<endl;
(2)int和double参加运算,int转为double
(3)char和short只要参加运算,就将自己转为int类型;因为char和short的运算容易越界
强制类型转换
(类型说明符)(表达式)
(int)p+1 对p强制转换成int类型,然后再+1
(int)(p+1) 将p+1强制转换为int类型
无论是自动转换还是强制转换,都是临时的,不影响原变量