1,函数指针和指针函数
主体(是函数还是指针) 需求
指针函数 函数 返回类型为指针
函数指针 指针 指向一个函数
//注意:()的优先级大于 *
int* f(int x,int y); 首先是一个函数,返回一个指针
int (*f)(int x,int y); 首先f是一个指针,指向是一个函数
#include <iostream>
using namespace std;
//指针函数
int* add(int x, int y)
{
int c = x + y;
return &c;
}
int sub(int x, int y)
{
return x + y;
}
//函数指针
int (*f1)(int x, int y);//指向函数
int* (*f2)(int x, int y);//指向函数指针
int main()
{
f1 = sub;
f2 = add;
cout << (*f1)(1, 2) << endl;
cout << *(*f2)(1, 2) << endl;
}
2,随机数
#include <ctime>
srand((int)time(NULL));
int a = rand()%100 + 20;
3,typedef
作用:给类型起别名
优点:方便
用法:typedef 类型 别名;
#include <stdio.h>
typedef int INT;
typedef struct {
int a;
int b;
}p1;
int main()
{
INT a = 3;
p1 p[6] = { {.a = 1,.b = 2},
{.a = 1,.b = 2},
{.a = 1,.b = 2},
{.a = 1,.b = 2},
{.a = 1,.b = 2},
{.a = 1,.b = 2}};
return 0;
}
4,C语言中malloc,calloc,realloc的使用
(1)malloc函数。其原型void *malloc(unsigned int num_bytes);
(2)calloc函数,其原型void *calloc(size_t n, size_t size);
(3)realloc函数和上面两个有本质的区别,其原型void realloc(void *ptr, size_t new_Size)
int *p1 = (int *)malloc(sizeof(int) * 4);
int *p2 = (int *)calloc(4, sizeof(int));
int *p3 = (int *)realloc(p1, sizeof(int) * 5);
//使用calloc开辟二维数组空间
#include <stdio.h>
#include <stdlib.h>
int main() {
int** p = (int**)calloc(4, sizeof(int));
if (p == NULL) return;
for (int i = 0; i < 4; ++i) {
p[i] = (int*)calloc(4, sizeof(int));
if (p[i] == NULL) return;
for (int j = 0; j < 4; ++j) {
printf("%d ", p[i][j]);
}
printf("%\n");
}
}
/*
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
*/
5,=default的含义
在C++11 新标准中,如果我们需要默认的行为,那么可以通过在参数列表后面写上 =default 来要求编译器生成构造函数。
class A
{
public:
A() = default;//需要默认构造
A(int x); //有参构造
};
6,文件输入输出
ifstream 读文件
ofstream 写文件
文件模式
in
以读的方式打开
out
以写的方式打开
app
每次写操作前均定位到文件末尾
ate
打开文件后立即定位到文件末尾
trunc
截断文件
binary
以二进制方式进行IO
is_open();//判断文件是否打开
7,常见容器操作
c.push_back()
尾部插入元素
c.push_front()
头部插入元素
c.pop_back()
删除尾部元素
c.pop_front()
删除头部元素
c.erase(p)
删除迭代器p指定的元素
c.erase(b,e)
删除迭代器b和e所指定范围内的元素
c.clear()
删除所有元素。返回void
c.empty()
判断c是否为空
c.resize()
c.resize(n)
c.resize(n,t)
增大或缩小容器
调整c的大小为n个元素
调整c的大小为n个元素,任何新添加的元素都初始化为值t
s.find(a)
查找s中a第一次出现的位置
s.rfind(a)
查找s中a最后一次出现的位置
8,lambda表达式
[capture list](parameter list)-> return type { function body}
capture list:捕获列表
parameter list:参数列表
return type:返回类型
function body:函数体
注意:可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体;
一个lambda只有在其捕获列表中捕获一个它所在函数中的局部变量,才能在函数中使用该变量
&引用捕获,=值捕获;
int a = 10;
//值捕获
auto f = [10](int x, int y) {return x + y; };
//引用捕获
auto f2 = [&a](int x, int y) {a = 11;return a + x + y; };
cout << "a=" << a << endl;//10
cout << "f(1, 2)=" << f(1, 2) << endl;//3
cout << "f2(1, 2)=" << f2(1, 2) << endl;//14
#include <iostream>
using namespace std;
void test01()
{
//lambda常用用法
auto fun1 = []()->int{ return 666; };
cout << fun1();
auto fun = [] () {return 666; };
cout << fun();
}
void test02()
{
int a1 = 0; int a2 = 1;
auto fun = [](int x, int y) {return x > y ? x : y; };
auto fun1 = [a1, a2](int x, int y) {return x > a2 ? "大" : "小"; };
}
void test03()
{
int sum = 0; int sum2 = 4;//lambda内部不可修改捕获的值
auto fun0 = [sum]() {return sum; };//值捕获
auto fun1 = [&sum](){return sum; };//引用捕获
auto fun2 = [=]() {return sum; };//隐式捕获-值捕获
auto fun3 = [&](){return sum; };//隐式捕获-引用捕获
auto fun4 = [=,&sum](){return sum; };//混合 捕获列表的第一个元素必须是一个&或=,此符号制定了默认捕获方式
sum = 1;
cout << "fun0: " << fun0() << endl;//sum = 0;
cout << "fun1: " << fun1() << endl;//sum = 1;
cout << "fun2: " << fun2() << endl;//sum = 1;
}
void test04()
{
//可变lambda 再lambda表达式内部可以修改捕获的值
int sum = 0;
auto fun = [sum]()mutable {return sum++; };
//指定lambda返回类型
auto fun1 = [](int i)->int {return 0; };
}
int main()
{
test04();
return 0;
}
9,constexpr和const关键字
const修饰普通类型的变量:
const int a = 0;a不可修改
const 修饰指针变量:
const 修饰指针变量有以下三种情况。
A: const 修饰指针指向的内容,则内容为不可变量。
B: const 修饰指针,则指针为不可变量。
C: const 修饰指针和指针指向的内容,则指针和指针指向的内容都为不可变量。
const 修饰成员函数
C++ 成员函数末尾的const
const:常量,在成员函数后面增加一个const。不单要在成员函数声明中增加const,也要在函数定义中增加const。
作用:告诉系统,这个函数,不会修改对象里的任何成员变量的值等等。也就是说,这个成员函数,不会修改类Time的任何状态。
成员函数后面加const的成员函数也称为“常量成员函数”。
const和constexpr区别:
C++ 11标准中,为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字。因此 C++11 标准中,建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。
可以看到,程序中用 const 修饰了 con_b 变量,表示该变量“只读”,即无法通过变量自身去修改自己的值。但这并不意味着 con_b 的值不能借助其它变量间接改变,通过改变 a 的值就可以使 con_b 的值发生变化。
10,运算符重载
习惯上人们是使用 cin>> 和 cout<< 的,得使用友元函数来重载运算符,如果使用成员函数来重载会出现 d1<<cout; 这种不自然的代码。
#include <iostream>
using namespace std;
class People
{
public:
friend ostream& operator<<(ostream& is, People& p);//重载<<
friend istream& operator>>(istream& is, People& p);//重载>>
bool& operator==(People& p);//重载==
People& operator+(People& p);//重载+
People& operator-(People& p);//重载-
People& operator*(People& p);//重载*
People& operator/(People& p);//重载/
People() = default;
People(int a, int b)
{
this->m_A = a;
this->m_B = b;
}
int m_A;
int m_B;
};
ostream& operator<<(ostream& is, People& p)//类外定义
{
is << p.m_A << endl;
is << p.m_B << endl;
return is;
}
istream& operator>>(istream& is, People& p)
{
is >> p.m_A;
is >> p.m_B;
return is;
}
bool& People::operator==(People& p)//重载==
{
bool temp = this->m_A == p.m_A && this->m_B == p.m_B;
return temp;
}
People& People::operator+(People& p)//重载+
{
this->m_A = this->m_A + p.m_A;
this->m_B = this->m_B + p.m_B;
return *this;
}
People& People::operator-(People& p)//重载-
{
this->m_A = this->m_A - p.m_A;
this->m_B = this->m_B - p.m_B;
return *this;
}
People& People::operator*(People& p)//重载*
{
this->m_A = this->m_A * p.m_A;
this->m_B = this->m_B * p.m_B;
return *this;
}
People& People::operator/(People& p)//重载/
{
this->m_A = this->m_A / p.m_A;
this->m_B = this->m_B / p.m_B;
return *this;
}
int main()
{
People p(1, 2);
People p2(1, 4);
//cin >> p;
//cout << p << endl;
//bool temp = p2 == p;
//cout << temp<< endl;
People p3 = p2 / p;
cout << p3 << endl;
}
11,为什么父类指针可以指向子类?
可以通俗的理解,子类可能含有一些父类没有的成员变量或者方法函数,但是子类肯定继承了父类所有的成员变量和方法函数。
所以用父类指针指向子类时,没有问题,因为父类有的,子类都有,不会出现非法访问问题。但是如果用子类指针指向父类的话,一旦访问子类特有的方法函数或者成员变量,就会出现非法。虽然父类指针可以指向子类,但是其访问范围还是仅仅局限于父类本身有的数据,那些子类的数据,父类指针是无法访问的。
使用函数指针实现父类函数调用子类函数的两种方式:
父子类关系
对于继承关系中的父类和子类,我们可以说子类是父类的一种,子类继承了父类的属性和行为。因此,子类可以访问父类的所有非私有成员。相反,父类一般情况下是不能访问子类成员的。然而,我们可以通过一些方法间接的实现父类访问子类,即父类函数访问子类函数。
方法一
利用多态机制,一个指向子类的父类指针或引用,当调用被子类重写的虚函数时,实际上调用的是子类函数,这是通过多态的方式来实现父类调用子类,该方法需要一个引用或者指针调用虚函数来实现。
方法二
通过函数指针同样可以实现父类函数访问子类函数
12,延时函数
#include <ctime>
void sleep(int time)//1000 = 1s;
{
clock_t head = clock();
while (clock() - head <= time)
{
}
}
13,时间打印
#include <iostream>
#include<iomanip>//前置补零
//#include<time.h>
#include <ctime>
#include <stdio.h>
using namespace std;
//延时函数
void sleep(int time)//1000 = 1s;
{
clock_t head = clock();
while (clock() - head <= time)
{
}
}
int main()
{
while (true)
{
time_t t;
t = time(NULL);
tm tt;
localtime_s(&tt, &t);
cout << tt.tm_year + 1900 << "-"
<< setw(2) << setfill('0') << tt.tm_mon + 1 << "-" //范围0~11 所以需要加 1
<< setw(2) << tt.tm_mday << " "
<< setw(2) << tt.tm_hour << ":"
<< setw(2) << tt.tm_min << ":"
<< setw(2) << tt.tm_sec <<"\r";//覆盖原始信息
sleep(1000);//延时更新
//getchar();//按 enter 更新
}
}
14,实现暂停效果
getchar();//获取字符
system(“pause”);//按任意键继续
system(“cls”);//清屏操作
15,C++中using的三种用法
1,导入命名空间
using namespace std;// 导入整个命名空间到当前作用域
using std::cout; // 只导入某个变量到当前作用域
2,指定别名
C++ 11 通过 using 指定别名,作用等同于 typedef,但相比 typedef,逻辑更直观,可读性更好。
typedef int T; // 用 T 代替 int
using T = int; // 用 T 代替 int
3,在派生类中引用基类成员
尽管派生类 对基类是私有继承,但通过 using 声明,派生类的对象就可以访问基类的 proteced 成员变量和 public 成员函数了。
16,sprintf_s(),sprintf()和printf()区别和用法
- printf函数把结果输出。
- sprintf函数把结果输出到指定的字符串中。
- sprintf_s()是sprintf()的安全版本,通过指定缓冲区长度来避免sprintf()存在的溢出风险
- sprintf_s 会检查格式化字符的合法性,而sprintf只会检查其是否是空指针
#include<stdio.h>
int main(int argc, char *avgv[])
{
char s[40];
sprintf(s,"%s%d%c","test",1,'2');
//第一个参数就是指向要写入的那个字符串的指针,剩下的就和printf()一样
char buff[256];
sprintf_s(buff,256, "../cfg/%d_%d.png", i, j);
printf("%s%d%c","test",1,'2');
//对保存后的字符串输出
printf("%s",s);
return 0;
}
17,C++ 字符和字符串(string,char)
1, C++ 内置函数(字符,数字转换)
- islower(char c) 是否为小写字母
- isupper(char c) 是否为大写字母
- isdigit(char c) 是否为数字
- isalpha(char c) 是否为字母
- isalnum(char c) 是否为字母或者数字
- toupper(char c) 字母小转大
- tolower(char c) 字母大转小
2,C++ 数字字符与数字相互转换
因为ASC码48就是’0’,也就是说’0’的值是48,而后依次是’1’到’9’。这样正好是char型减去48就是它对应的int值 int data = s[i] - ‘0’;或者int data = s[i] - 48;
3,字符串转换为数字:int atoi(char *);
4, 去除string头尾空白函数
string& trim(string &s)
{
if (s.empty()) return s;
s.erase(0,s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
return s;
}
18,vector 容器去重
1,结合sort和unique函数
unique()函数将相邻且重复的元素放到vector的尾部 然后返回指向第一个重复元素的迭代器再用erase函数擦除从这个元素到最后元素的所有的元素。
vector<int> vec;
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
2,利用set的特性
vector<int> vec;
set<int> s(vec.begin(), vec.end());
vec.assign(s.begin(), s.end());
19,进制转换(二进制,八进制,十六进制)
void 进制表示() {
int a = 0b1001;//二进制表示 0b
int b = 01001;//八进制表示 0
int c = 0x1001;//十六进制表示 0x
cout<<"a = " << a << endl;
cout<<"b = " << b << endl;
cout<<"c = " << c << endl;
}
void 进制输出() {
int a = 13;
a = a | 0b10;
cout << bitset<10>(a) << endl;//二进制输出
cout << hex << a << endl;//十六进制输出
cout << oct << a << endl;//八进制输出
}