一、c++基础
1.1 面向过程、面向对象
简单来说,面向过程是对一个“步骤”进行开发,而面向对象是对一个“函数”进行开发。
程序=数据+算法
1.2 输入、输出
#include <iostream> //包含头文件:输入、输出流
using namespace std; //打开(使用) 标准命名空间
int main() {
int a ;
//cin istream 某个类型的变量
//>> 输入操作符 本质上是一个函数
cin >> a;
//cout ostream 某个类型的变量
//<< 输出操作符 本质上是一个函数
//endl 换行 本质上是一个函数
cout << a << endl;
}
1.3 作用域
#include <iostream>
using namespace std;
int a = 1; //全局
namespace AA { //命名空间,划分一个小的作用域
int a = 2;
}
using namespace AA;
int main() {
int a = 0; //局部
cout << a << endl;
//:: 作用域运算符 某个作用域 :: 成员
//前不加任何作用域,默认使用全局作用域
//常见作用域:结构体 类 命名空间
cout << ::a << endl;
std::cout << AA::a << endl;
{
using AA::a; //在这个作用域中,遇到未指定作用于的a,默认使用AA::a
cout << a << endl;
}
}
1.4 动态申请空间
#include <iostream>
using namespace std;
int main() {
//C 动态申请空间
int* p = (int*)malloc(sizeof(int)); //堆区
cout << *p << endl;
*p = 1; //赋值
cout << *p << endl;
free(p); //释放
p = NULL;
//c++ 使用new、delete关键字动态申请空间
int* q = new int; //堆区
cout << *q << endl;
*q = 2;
cout << *q << endl;
delete q;
q = NULL;
int* arr = new int[4]{ 1,2,3,4 }; //数组返回首元素首地址
for (int i = 0; i < 4; i++)
cout << arr[i];
delete []arr;
arr = NULL;
short* ps = new short(2); //new short 并且使用()或{}做一个初始化
cout << *ps << endl;
/*
const char *p="123";
cout<<p; //123
cout<<(void*)p; //地址
*/
}
malloc -free
1、本质上是函数,需要头文件的支持
2、是函数,参数需要传递 申请空间的大小(字节),返回时void*,一般情况下需要强转
3、默认不初始化
4、malloc申请结构体、类 对象并不会调用构造函数,free不会调用析构函数
new -delete
1、本质上是关键字(c++),需要对应的编译器支持
2、后面接所需的类型,返回值是对应类型的地址
3、可以指定初始化
4、申请结构体、类 对象会自动调用构造函数 析构函数
//new 整型的指针
int** p1 = new int*;
delete p1;
p1 = NULL;
//char指针 数组
char** p2 = new char* [5];
delete[]p2;
p2 = NULL;
// char 数组 指针
char(**p3)[5] = new (char(*)[5]);
delete[]p3;
p3 = NULL;
typedef char(*P_ARR)[5];
P_ARR* p4 = new P_ARR;
delete p4;
p4 = NULL;
// int 二维数组
int(*p5)[3] = new int[2][3]; //注意首元素地址
delete[]p5;
p5 = NULL;
// new 函数指针
void(*p_fun)() = &fun;
void(**p6)() = new (void(*)());
*p6 = &fun;
delete p6;
p6 = NULL;
1.5 bool类型
#include <iostream>
#include <Windows.h>
using namespace std;
int main() {
//typedef int BOOL
BOOL b = TRUE;
cout << sizeof(b) << sizeof(BOOL) << endl; //4 4
bool bb = true; //c++中的bool类型
bb = false;
cout << sizeof(bb) << sizeof(bool) << endl; //1 1
}
1.6 字符串
#include <iostream>
#include <string>
using namespace std;
int main() {
const char* p = "123";
//字符串常量,不可以被修改
cout << p << " " << (void*)p << endl;
char* parr = new char[5]{ "1234" };
parr[1] = 'b';
cout << parr << endl;
const char* pp = "1b34";
cout << strcmp(parr, pp) << endl;
string str = "789";
str[1] = 'r';
cout << str << endl;
string str1 = "123";
string str2 = "123";
cout << (str1 == str2) << endl;
str2 = str + p + parr; //使用+ +=做字符串拼接
cout << str2 << endl;
cout << str2.substr(1, 4) << endl; //起始下标,截取长度
//下标超界 -> 数组越界
cout << str2.find("b34") << endl; //返回起始下标
cout << str2.rfind("b34") << endl; //反向查找子串
cout << str2.size() << ' ' << str2.length() << endl;
str2.clear();
cout << str2.size() << ' ' << str2.length() << endl;
}
1.7 增强范围for
#include <iostream>
using namespace std;
int main() {
int arr[3] = { 1,2,3 };
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
cout << arr[i] << ' ';
}
cout << endl;
for (int v: arr) { //增强范围for
cout << v << ' ';
}
cout << endl;
//增强范围for必须得知道大小,通过指针无法知道大小
int* p = new int[5]{ 1,2,3,4,5 };
for (int i = 0; i < 5; i++) {
cout << p[i] << ' ';
}
cout << endl;
//还可以遍历 支持begin end 操作的容器
}
1.8 函数参数默认值
#include <iostream>
using namespace std;
void fun(int a=10) { //在c++中,函数的参数可以指定默认值
cout << "fun:" << a << endl;
}
//多个形参指定默认值,顺序要求:从右向左依次指定,中间不可以有间断
void fun(int a, int b, int c=200) {
cout << "fun:" << a << " " << b << " " << c << endl;
}
int main() {
fun(1);
fun(); //不传递实参,使用的是默认值
}
1.9 函数重载
函数重载 :在同一个作用域下,函数名相同,参数列表不同(类型,数量,顺序),对于返回类型并没有任何的要求.
注意几种不是重载的情况
//不是函数重载
//已有主体 错误
void fun1(int a) {
cout << a << endl;
}
void fun2(const int a) { //const只是用来描述不可被修改
cout << "const int " << a << endl;
}
//已有主体 错误
//本质上 都是地址
void fun2(int arr[]) {
cout << "arr[]" << endl;
}
void fun2(int* arr) {
cout << "*arr" << endl;
}
对于参数相同的函数,想要对其进行函数重载,需要进行情况区分,函数局部化声明
void fun() {
cout <<"fun"<< endl;
}
void fun(int a = 10) {
cout << "a=" << a << endl;
}
int main(){
void fun();
fun(); //"fun"
{
void fun(int a = 30);
fun(); //30
fun(20); //20
}
}
1.10 nullptr
nullptr 和 NULL的区别
1. nullptr 是关键字,NULL 宏 替换了 数字0 , #define NULL 0
2. nullptr 有着明确的含义,空指针 ,NULL 数字0
#include <iostream>
using namespace std;
void fun(int a) {
cout << "int a " << a << endl;
}
void fun(int *p) {
cout << "int* p " << p << endl;
}
int main() {
int* p = NULL; //#define NULL 0
/*NULL 既可以代表空指针,也可以表示整型数字0
在函数重载的情况下,优先匹配整型
造成了整型数字0 和空指针含义混用的问题*/
fun(p); //int* p 00000000
fun(NULL); //int a 0
//nullptr C++中关键字 代表的含义是空指针
fun(nullptr); //int* p 00000000
}
当出现多个指针参数时,使用nullptr会出现 "多个重载函数实例与参数列表匹配" 的错误。需要将nullptr进行强制类型转换。
void fun(int *p) {
cout << "int* p " << p << endl;
}
void fun(char* p) {
cout << "int* p " << p << endl;
}
fun((int*)nullptr); //如果遇到多个不同类型指针的情况下,强转为具体类型的指针
fun((char*)nullptr);
1.11 引用
引用:对某一个变量 或 已存在空间 起别名
#include <iostream>
using namespace std;
void fun(int& c) { //指针
cout << c << " " << &c << endl;
c++;
}
void fun(int d) {
cout << d << " " << &d << endl;
d++; //值传递copy,修改只是修改了形参
}
void fun(int* p) {
cout << *p << endl;
*p = 6;
}
int main() {
int a = 1;
int& b = a; //& 定义引用的含义
&a; //取地址
int c = 3;
{
void fun(int& c);
fun(c);
}
cout << c << " " << &c << endl;
void(*p_fun1)(int&) = &fun;
void(*p_fun2)(int) = &fun;
(*p_fun1)(c);
cout << c << " " << &c << endl;
(*p_fun2)(c);
cout << c << " " << &c << endl;
int d = 1;
fun(&d);
cout << d << endl;
}
注意:函数名相同的,参数是 某一个类型 和 同类型的引用,是函数重载
对于这种重载,直接进行调用的时候会出现参数匹配的二义性,此时会出现 ”多个重载函数与参数列表匹配“ 的错误。
可以通过 ”函数声明 局部化“ 和 ”函数指针“的方式来区分这两种重载。
函数传参的三种方式:
1、值传递:只能查看 不能修改实参,对实参的拷贝一份,会额外申请不定大小的空间
2、指针传递:既可以查看又可以修改实参,是存储实参变量的地址,会额外申请 指针大小的 (可控)的空间。 3、引用传递:既可以查看又可以修改实参,直接引用实参,并不会额外申请空间。推荐使用引用传递。
区别:
1、指针可以为空,引用不可以为空。
2、指针 可以随意指向某个变量,也可以更改指向,但是 引用一旦用某一个变量,则不可修改。
3、指针 存储地址需要指针大小空间,引用不会额外申请空间。
4、指针可以有多级,引用没有多级引用的说法 5、引用必须有初始化,指针可以没有初始化
//int& d; //引用 变量 "d" 需要初始值设定项
int e=1;
int& f=e;
int h=2;
f=h; //是赋值,并不是重新引用其他变量
int&& b=a;右值引用