变量作用:给一段指定的内存空间起名,方便操作这段内存。
常量:用于记录程序中不可更改的数据。
#include <iostream>
using namespace std;#define DAY 7
int main() {cout << "一周有" << DAY << "天" << endl;const int hour = 24;cout << "一天有" << hour << "小时" << endl;return 0;
}
在给变量或常量起名时,不用使用关键字。
整型有几种类型,区别是占用内存空间不同
#include <iostream>
using namespace std;int main() {cout << sizeof(short) << endl;cout << sizeof(int) << endl;cout << sizeof(long) << endl;cout << sizeof(long long) << endl;return 0;
}
科学计数法以10为底
float f2 = 3e2;
float f3 = 3e-2;
cout << f2 << endl;
cout << f3 << endl;
C和C++中字符型变量只占用1个字节。
字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元
字符串型
#include <iostream>
using namespace std;int main() {char str[] = "1111";cout << str << endl;string str2 = "2222"; cout << str2 << endl;return 0;
}
数组特点
放在一块连续的内存空间中,数组中每个元素都是相同数据类型。
如果在初始化时候,没有全部填写完,会用0来填补剩余数据。
一维数组数组名
冒泡排序
- 比较相邻的元素,如果第一个比第二个大,就交换他们。
- 对每一对相邻元素做相同工作,执行完毕后,找到第一个最大值。
- 重复以上步骤,每次比较次数-1,直到不需要比较。
值传递
所谓值传递,就是函数调用时实参将数值传入给形参。
值传递时,如果形参发生改变,并不会影响实参。
函数的声明
作用:告诉编译器函数名称以及如何调用函数。函数的实际主体可以单独定义。
声明可以有多次,但是定义只能有一次。
空指针
指针变量指向内存中编号为0的空间。
用途:初始化指针变量
空指针指向的内存是不可以访问的。
内存编号0~255是系统占用的,用户不允许访问。
利用指针作函数参数,可以修改实参的值。
值传递不会改变实参,地址传递会改变实参。
结构体
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。
C++中创建结构体变量时,关键字struct可以省略。
结构体指针
#include <iostream>
using namespace std;struct Student {string name;int age;int score;
};
int main() {Student student = { "小苹苹",18,100 };Student* p = &student;cout << p->name << endl;return 0;
}
引用的本质,就是一个指针常量。
所以引用一旦初始化后,就不可以发生改变。
常量引用
常量引用主要用来修饰形参,防止误操作。
在函数形参列表中,可以加const修饰形参,防止形参改变实参。
void showValue(const int &value){//value++;cout << value << endl;
}
函数默认参数
在C++中,函数的形参列表中的形参可以有默认值
函数重载
作用:函数名可以相同,提高复用性。
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者个数不同或者顺序不同
C++面向对象的三大特征:封装、继承、多态
实例化:通过一个类,创建一个具体对象的过程。
类中的属性和行为,统一称为成员。
struct和class区别
唯一的区别就在于默认的访问权限不同。
区别:
- struct:默认权限为公共
- class:默认权限为私有
将成员属性设置为私有
可以自己控制读写权限
构造函数
- 没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,可以发生重载
- 会自动调用构造,而且只会调用一次
类名(){}
析构函数
~类名(){}
析构函数不可以有参数,因此不可以发生重载
如果利用编译器提供的拷贝构造函数,会做浅拷贝操作。
浅拷贝带来的问题就是堆区的内存重复释放。
~Person(){if(m_Height != NULL){delete m_Height;m_Height = NULL;}
}
浅拷贝的问题要利用深拷贝进行解决。
Person(const Person& p){Person.m_Height = new int(*p.m_Height);
}
- 浅拷贝:简单的赋值拷贝操作
- 深拷贝:在堆区重新申请空间,进行拷贝操作
如果有属性在堆区开辟,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。
环形链表
给一个链表的头节点head,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。
哈希表
最容易想到的方法是遍历所有节点,每次遍历到一个节点时,判断该节点此前是否被访问过。
可以使用哈希表来存储所有已经访问过的节点。
每次我们到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表中,重复这个过程。
区分黑球与白球
桌子上有n个球,每个球的颜色不是黑色,就是白色。
给一个长度为n,下标从0开始的二进制字符串,其中1就是黑球,0就是白球。
在每一步中,可以选择两个相邻的球并交换他们。
将所有黑球移到右侧,白球移到左侧,所需要的最小步数。
贪心
交换完后的最终状态一定是形如00001111,那么便利字符串的时候,每碰到一个0就贪心的将其往左交换,直到它到达最终的位置。
字符串中的额外字符
给一个下标从0开始的字符串s和一个单词字典序dictinary。
动态规划
题目要求将字符串s分割成若干个互补重叠的子串,并且子串必须在dictinary中出现。
一些额外的字符可能不属于任何子串。
题目要求最小化这些额外字符的数量。
设n是s的长度,现在有两种基本的分割方案:
- 把s的最后一个字符s[n-1]当做是额外字符,那么问题转换为长度为n-1的子问题。
- 找到一个j使得s的后缀s[j…n-1]构成的子串在dictionary,那么问题转换为j-1的子问题。
因此,定义d[i]为s前缀[0,…,i-1]的子问题,那么d[i]取下面情况的最小值。
- 把s[i-1]当做是额外字符,d[i] = d[i-1]+1。
- 遍历所有的j,如果s[j…i-1]在dictinary,那么d[i] = mid d[j]
C++编译器至少给一个类添加4个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
- 赋值运算符operator=,对属性进行值拷贝
如果类中有属性指向堆区,做赋值操作时也会出现深浅拷贝问题。
函数调用运算符重载
- 函数调用运算符()也可以重载
- 由于重载后使用的方式非常像函数的调用,因此称为仿函数
- 仿函数没有固定写法,非常灵活
匿名对象
类名()
当前行执行完,立即被释放。
子类继承父类后,当创建子类对象时,也会调用父类的构造函数
创建一个子类对象时,先调用父类构造,再调用子类构造,析构顺序相反。
继承同名成员处理
- 访问子类同名成员:直接访问即可
- 访问父类同名成员:需要加作用域
C++允许一个类继承多个类
菱形继承
两个派生类继承同一个基类,又有某个类同时继承两个派生类,这种继承被称为菱形继承。