C++要领

#扩展名

常见的有C、c、cxx、cpp、c++等,注意,UNIX区分大小写,这意味着应使用大写的C字符。实际上,小写c扩展名也有效,但标准C才使用小写的c。因此,为避免在UNIX系统上发生混淆,对于C程序应使用c,而对于C++程序则请使用C。如果不在乎多输入一两个字符,则对于某些UNIX系统,也可以使用扩展名cc和cxx

# 注释

// 单行注释
/*
	多行注释
*/

# 函数

函数使用前先声明,或者include头文件

#include <iostream>// 使用cin和cout必须包含
#include <cmath>

int main() {
    using namespace std;// 名称命名空间
/*	
	using std::cin;
	using std::cout;
    using std::endl;	效果等同
*/	
    
/*
	 std::cout << "abc" << site << " feet to the side." << std::endl;	效果等同
*/
    double area;
    cout << "enter the floor area, in square feet,of your home:";
    cin >> area;
    double site = sqrt(area);
    cout << "that's th equivalent of a square " << site << " feet to the side." << endl;
    cout << "how fascinating" << endl;

    return 0;
}

C++能够使用printf( )、scanf( )和其他所有标准C输入和输出函数,只需要包含常规C语言的stdio.h文件。C++的输入工具它们在C版本的基础上作了很多改进。

# 简单变量

# 整型

short、int、long、longlong、unsigned系列

#include <iostream>
#include <climits>

int main() {
    using namespace std;
    int n_int = INT_MAX;
    short n_short = SHRT_MAX;
    long n_long = LONG_MAX;
    long long n_llong = LLONG_MAX;

    cout << sizeof(int) << " bytes" << endl;
    cout << sizeof(short) << " bytes" << endl;
    cout << sizeof(long) << " bytes" << endl;
    cout << sizeof(long long) << " bytes" << endl;
    cout << "Max values" << endl;
    cout << n_int << endl;
    cout << n_short << endl;
    cout << n_long << endl;
    cout << n_llong << endl;

    return 0;
}
/*
4 bytes
2 bytes
4 bytes
8 bytes
Max values
2147483647
32767
2147483647
9223372036854775807
*/

确定常量的类型

cout << "year = " << 1492 << "\n";// 默认int存储1492

char:特殊的整型

# 字符和字符串

'a'是字符

"a"是字符串

# 布尔类型

布尔转为整型

int ans = true; // 赋值为1
int ans = true; // 赋值为1

整型转为布尔

bool start = -100;// true
bool stop = 0;// false

# const 限定符

const int Months = 12;// 定义时候就得初始化

Months变成了只读变量,即使常量

相比#define好在知道指定了类型,且限定作用域内起作用

# 特殊初始化语法

区别于 C 语言的初始化方法

#include <iostream>
#include <climits>

int main() {
    using namespace std;
    int a = 100;
    cout << a << endl;
    int b(10);
    cout << b << endl;
    int c{1};
    cout << c << endl;
    return 0;
}

# 类型转换

# 类型转换的规则

{}是列表初始化,不允许缩窄()

在计算表达式,会进行int提升(bool、char等转换成int)

小范围和大范围运算会转为大范围

强制类型转换:

(long) a // 强制转换类型1,临时作用 --C语言风格
long (a) // -- C++风格
static_cast<long> (a) // --强制类型转换形式2 

# 自动判断类型 auto声明

auto n = 100; // int
auto a = 1.0; // double
autp y = 1.3e12L; // long double

# 数组

# 三要素

  1. 每个元素的类型
  2. 数组名
  3. 元素数量

# 声明

short mouth [12];

其中12元素数量必须已知,不可为变量(但是可以const int Size声明常量)

# 初始化规则

只能在定义数组的时候初始化,可以少于数组数目

int cards[4] = {3,6,8}; // 允许,序号3元素为0
int bards[] = {3,6,8}; // 允许,有三个元素
/*
int hards[4];
hards[4] = {3,6,7,8}; -- 不允许
hards = cards; -- 不允许
*/

可以单个元素赋值

cards[1] = 3;

C++11中=可省略

int bards[] {3,6,8};

{}列表初始化,不允许缩窄

char mards[] = {32342344,6,8}; // 32342344超出范围

# 计算数组的元素个数

int count = sizeof(a) / sizeof((a[0]));

解释:sizeof(a) 返回数组 a 在内存中的总字节数,sizeof(a[0]) 返回数组 a 中第一个元素的字节数。

字符串的话/0也会计算进去

# 字符串

字符串是以\0结尾的数组

char cat[] = {'f','a','t','e','s','s','a','\0'};
char fish[] = "Bubbles";

注意:'' 表示字符,""表示字符串,不可互换

空白自动拼接两字符串

strlen()计算字符串长度(没有\0),区分sizeof()

# 读取字符串

cin通过空白字符判断结束

cin.getline(name,20)放入name,读取20-1个字符 – 面向行输入(回车终止并且丢弃回车)

cin.get(name,20)放入name,读取20-1个字符 – 面向行输入(回车终止并且保留回车,无法跨越回车)

cin.get(name,20);// 不可处理回车
cin.get();// 可处理回车

cin.get(name,20).get();// 写法2处理回车

cin.clear();// 复位失效位

# string 类

#include <iostream>
#include <string>

int main(){
	using namespace std;
	char charr1[20];
	char charr2[20] = "jaguar";
	string str1;
	string str2; = "panther";
	cout << "Enter another kind of feline:";
	cin >> charr1;
	cout << "Enter another kind of feline:";
	cin >> str1;
	cout << "Here are some felines:\n";
    
	cout << charr1 << " " << charr2 << " " << str1 << " " << str2 << endl;
    
	cout << "The third letter in " << charr2 << "is" << charr2[2] << endl;
    cout << "The third letter in " << str2 << "is" << str2[2] << endl;
	
	return 0;
}

string和字符数组的处理方式相同

string会自动调节数组大小

一个string可以赋予另一个string对象

#include <iostream>
#include <string>
#include <cstring>

int main(){
	using namespace std;
	char charr1[20];
	char charr2[20] = "jaguar";
    string s1 = "aaa";
    string s2,s3; 
    s2 = s1;
    cout << s2 << endl;
    strcpy(charr1,charr2);//charr2->charr1复制

    s3 = s1 + s2; // 字符串拼接
  	s3 += "hahaha"; // 拼接到末尾
    strcat(charr1,"ccc");// 拼接到末尾	
    
    int len1 = str1.size();//string风格计算字符
    int len2 = strlen(charr1);//C风格计算字符
    
    
	return 0;
}

# string 类IO

#include <iostream>
#include <string>
#include <cstring>

int main(){
	using namespace std;
	char charr[20];
	string str;
	cout << "length:" << strlen(charr1) << endl; // 报错,因为计算的是到下一个\0
	cout << "length:" << str.size() << endl;

	cout << "Enter:\n";
    cin.getline(charr,20);// 对于cin来说,getline是类方法
	cout << "Entered: " << charr << endl;
   	cout << "Enter:\n";
    getline(cin,str);// 对于string来说,getline是普通函数
	cout << "Entered: " << str << endl;
    cout << "length:" << strlen(charr1) << endl; // 报错,因为计算的是到下一个\0
	cout << "length:" << str.size() << endl;
	return 0;
}

cout遇到char字符串直接通过地址读内容

初始化字符串用=,其他情况用strcpy() strncpy()

 char animal[20] = "bear"
 ps = new char[strlen(animal)+1];
 strcpy(ps,animal);

简化输入:

using namespace std::string_literals; 允许我们直接使用s后缀来创建std::string对象,而无需写成std::string。

int main() {
    auto str = "Hello, World!"s; // 使用"s"后缀直接创建std::string对象
    return 0;
}

# 结构体

同一个结构可以存储多个类型的数据

创建结构分两步:①定义结构描述 ②按描述创建结构变量

注意:结构内容用,隔开,结构之间;隔开,;结尾

#include <iostream>
struct inflatable
{
    char name[20];
    float volume;
    double price;
};

int main(){
    using namespace std;
    inflatable hat; // 声明 inflatable 类型 hat
    hat.volume = 10.0;// 访问 hat 的 volume 成员

    inflatable guest = {
        "Glorious Gloria",
        1.88,
        29.90
    };
    
    inflatable g2;
    g2 = guest;// 成员赋值
    cout << "Expand your guest list with " << guest.name << endl;
    cout << "Expand your guest list with " << g2.name << endl;// 成员赋值y有效
    return 0;
}

# 结构数组

创建3个inflatable的数组:

#include <iostream>
struct inflatable
{
    char name[20];
    float volume;
    double price;
};
int main(){
    using namespace std;
    inflatable g2[2] = {
        {"Glorious Gloria",1.88,29.90},
        {"Glorious gg",1.44,29.4}
    };
    cout << "Expand your guest list with " << g2[1].name << endl;
    return 0;
}

# 共用体

可以存储不同类型,但是使用时只能同时存储一个

union one4all
{
	int int_val;
	long long_val;
	double double_val;
};
//double 最大,用double开辟内存空间

用处:可以表示商品ID(用字母、汉字、数字)

union id 
{
	long id_num;
	char id_char[20]; 
}

# 枚举

enum spectrum{red,orange,yellow,green,blue};
spectrum band;
band = blue;
band = 2000;// 错误
int color = band + 3;//可以提升到int band为5

# 设置枚举量值

enum bits{one = 1, two = 2, four = 4, eight = 8};

可以设置多个值相同的枚举

enum {zero,null=0};

# 取值范围

最大枚举量值的下一个最小二次幂,再减1:7就是8-1,16就是32-1

# 指针

*:

指针:是“指向”另外一种类型的复合类型,实现了对其他对象的间接访问。

解地址:解开某个对象的地址,获得该对象所占空间对应的值。

&:

引用:是“引用”另外一个类型的 复合类型,对已经存在的对象起另外一个名字,即为别名。

取地址:获得某个对象的地址。

int i = 42; int &r = i; //&紧随类型名出现,r是一个引用 
int *p; //*紧随类型名出现,p是一个指针
p = &r; //&出现在表达式,是一个取地址符
*p = i; // *出现在表达式,是一个解引用符 
int &r2 = *p //&紧随类型名出现,r2是一个引用;*出现在表达式,是一个解引用符 

总结:

*出现在声明语句时,*为复合类型指针的意思;

*出现在表达式时,*为运算符解引用的意思。

&出现在声明语句时,&为复合类型引用的意思;

&出现在表达式时,&为运算符取地址的意思。

定义:

int updates = 6;
int* p_updates = &updates;

float bb = 8.8;
float* p_bb= &bb;

以下都可以:

int* a;
int *a;
int*a;

指针赋值

long* fellow;
*fellow = 123;
//非法,fellow指向了不知道哪里的地址
int * pt;
pt = (int*) 0xB8000000;// 强制转换

# new 分配内存,delete 释放内存

开辟一个int类型的空间给pn指针

int* pn = new int;

new开辟的内存会一直存在,应该使用delete删除

int* ps = new int;
delete ps;

delete分配的内存删除,但是指针ps还在,可赋值其他内存

delete不允许删除非new创建的指针

# new 创建动态数组

创建动态数组

int* psome = new int[10];// psome 是首个元素的地址
delete [] psome;// 释放整个数组

此时可以指针当做数组名

int* psome = new int[3];
psome[0]= 66;
psome[1]= 88;
psome[2]= 77;
delete [] psome;

还可以移位

int* p3 = new int[3];
p3[0]= 66;
p3[1]= 88;
p3[2]= 77;
p3 = p3 + 1;
//p3[0]= 88;p3[1]= 77;
p3 = p3 - 1;
//p3[0]= 66;p3[1]= 88;
delete [] p3;

sizeof不会把数组名当做地址,会当成整个数组的大小

#include <iostream>
int main()
{
    using namespace std;
    int stacks[3] = {3,2,1};
    cout << "sizeof(stacks) = " << sizeof(stacks) << endl;// sizeof(stacks) = 12
    cout << "stacks[0] = " << &stacks[0] << endl;// 第一个元素的地址
    cout << "stacks = " << stacks << endl;// 数组首位元素的地址
    cout << "&stacks = " << &stacks << endl;// 是整个数组的地址,地址的长度是整个数组
    /*
    stacks[0] = 0xabb59ff714
    stacks = 0xabb59ff714
    &stacks = 0xabb59ff714
    */
    return 0;
}

# 创建动态结构

  1. 创建结构

    struct things
    {
    	int good;
    	int bad;
    };
    
  2. 访问成员

    things a = {3,453};
    things* pt = &a;
    //结构名.成员 指针->成员 访问成员的格式
    a.good = 1;
    pt->good = 2;
    (*pt).good = 3;
    

    动态调整

#include <iostream>
#include <string.h>
using namespace std;
char* getname();

int main()
{
    char* name;
    name = getname();
    cout << name << " at " << (int*)name <<endl;
	delete[] name;
    return 0;
}

char* getname()
{
    char temp[50];
    cout << "Enter your name: ";
    cin >> temp;
    char* pn = new char[strlen(temp) + 1];
    strcpy(pn, temp);
    return pn;
}

# 模板类 vector

可以自动调节内存

#include<vector>

using namespace std;
vector<int> vi;//不指定长度,自动调节内存
vector<double> vd(n);//指定长度

// 错误:vector<double> va(3) = {1.1,2.2,3.3};
vector<double> va = {1.1,2.2,3.3};//正确

# 模板类 array

长度固定,使用栈,功能和数组一样,但比数组方便安全

#include<array>

using namespace std;
array<int,5> ai;
array<double,4> ad = {1.2,2.1,3.3,4.4};

# 对比

vector<double> va = {1.1,2.2,3.3};
array<double,4> ad = {1.2,2.1,3.3,4.4};
va = ad;// 可行,对象可以互相赋值,但是地址分开

检测有无越界:

a2[-2] = 5;// 错误但不检查
a2.at(2) = 3;// 错误但检查,捕获索引

# 循环

作用域

int i = 10;// main的i
for (int i = 0 ; i < 5 ; i++){// 作用域内新i
	cout << i << endl;
}
int i;
for (i = 0; i < 10; i++) {// main已经声明i可以不用声明
    cout << i << endl;
}
int i=2;
for (; i < 10; i++) {//用的main的i
    cout << i << endl;
}

# 前后缀递增递减

++i先+1
i++,就是i,再说+1

一个分号就是一个顺序点,完整表达式末尾也是顺序点

while (guests++ < 10)// 比较完,在顺序点(进入循环前)+1
	cout << guests << endl;
for (n=1; n > 0 ; n++)
    cout << n << endl;
// 这里两个n的++前后没有区别,运行效率略微有区别
for (n=1; n > 0 ; ++n)
    cout << n << endl;

# 语句块

#include <iostream>

int main() {
    using namespace std;
    int a = 10;
    {
        int a = 100;
        cout << a << endl;// 显示新变量,隐藏外部变量
        int b = 100;// 局部变量,出局释放
    cout << a << endl;
}

# 逗号运算符

两个运算符合并成一个

for (j = 0 , i = word,size() - 1;j < i ; --i , ++j)
{
	temp = word[i];
	word[i] = word[j];
	word[j] = temp; 
	
}

# C 风格字符串比较

char word[] = "mate";
word == "mate";// 错误,是比较两个地址是否相等
strcmp("mate","made");// 字符串比较,相同为0

# String 比较

string word;
word != "mate";

# while 编写延时

#include <iostream>
#include <ctime>

int main() {
    using namespace std;
    cout << "delay time: " ;
    float seconds;
    cin >> seconds;
    clock_t delay = seconds * CLOCKS_PER_SEC;// clock_t是long,类型别名方便阅读代码
    cout << "begining" << endl;
    clock_t begin = clock();
    while (clock() - begin < delay);
    cout << "done" << endl;
}

# 类型别名

#define BYTE char
//全局替换所有的char为BYTE

typedef char byte;
typedef char* byte_pointer;
//直接用typedef替换
auto byte = 1;
//自动识别类型定义

# 基于范围的for循环

遍历列表

double prices[5] = {22.2,33.1,4.3,5.0};
for (double x : prices)// x 依次表示每一个元素
	cout << x << endl;
for (double &x : prices)// 遍历引用
	x = x * 0.8;// 可以直接xiu'gai

# 文件尾条件(EOF)

#include<iostream>
int main()
{
    using namespace std;
    char ch;
    int count = 0;
    cin.get(ch);
    while (cin.fail() == false)// 检测是否有EOF位
     // while (!cin.fail())// 简化1
     // while (cin.get(ch))// 简化2,返回cin转换为布尔
    {
        cout << ch;
        ++count;
        cin.get(ch);
    }
    cout << endl << count << endl;
    return 0;
}

EOF 在Windows是Ctrl+Z

重置用cin.clear()

区分有参数和无参数:

属性 cin.get(ch) ch=cin.get()
输入字符 字符赋值给ch 函数返回值赋给ch
读取到字符 cin对象(布尔转换为true) int类型的ASCII码
读取到EOF cin对象(布尔转换为false) EOF

# 二维数组和循环嵌套

int maxtemps[4][5]

maxtemps[4]是数组的数组
int[5]是int的数组

0 1 2 3 4
maxtemps[0] maxtemps[0][0] maxtemps[0][1] maxtemps[0][2] maxtemps[0][3] maxtemps[0][4]
maxtemps[1] maxtemps[1][0] maxtemps[1][1] maxtemps[1][2] maxtemps[1][3] maxtemps[1][4]
maxtemps[2] maxtemps[2][0] maxtemps[2][1] maxtemps[2][2] maxtemps[2][3] maxtemps[2][4]
maxtemps[3] maxtemps[3][0] maxtemps[3][1] maxtemps[3][2] maxtemps[3][3] maxtemps[3][4]
#include<iostream>
int main()
{
    using namespace std;
    int maxtemps[4][5] = {
        {22,33,44,55,66},
        {12,3666,4444,222,776},
        {211,331,2211,122,44},
        {4422,6655,3344,2252,12}
    };
    for(int i=0;i<4;i++)
        for(int j=0;j<5;j++)
            cout << maxtemps[i][j] << " ";
    return 0;
}

# 逻辑运算符

|| ,and:或,一真为真,前真后不执行,优先级低于关系运算符

&&,or:与,一假为假,前假后不执行,优先级低于关系运算符

!,not:非,取反,优先级最高,注意加括号

# cctype库函数

此部分出处:https://www.cnblogs.com/AlienfronNova/p/14528837.html

作者:摸鱼鱼的尛善

一、处理类

①tolower©

作用:将C转换为小写字母;若不能转换,不作任何变化返回ch

参数:ch为整型

char str[] = "Test STRING\n";
char c;
for(int i = 0;str[i];i++){
    c = str[i];
 	putchar (tolower(c));
}
//当str到最后也就是'\0'的时候,'\0'对应的就是0,放在循环里也就是代表false

②toupper(ch)

作用:将C转换为大写字母;若不能转换,不作任何变化返回ch

参数:ch为整型

char str[] = "tEST string\n";
char c;
for(int i = 0;str[i];i++){
    c = str[i];
 	putchar (toupper(c));
}

二、判断类

①isalnum(int ch)

作用:判断字符是否为数字、大写字母、小写字母。若是,返回非零的值;否则,返回0

参数:ch为整型

int flag = isalnum('3');
printf("%d",flag);

②isalpha(int ch)

作用:判断字符是否为大写字母、小写字母。若是,返回非零的值;否则,返回0

参数:ch为整型

③isupper(int ch)

作用:判断字符是否为大写字母。若是,返回非零的值;否则,返回0

参数:ch为整型

④islower(int ch)

作用:判断字符是否为小写字母。若是,返回非零的值;否则,返回0

参数:ch为整型

⑤isdigit(int ch)

作用:判断字符是否为数字。若是,返回非零的值;否则,返回0

参数:ch为整型

⑥iscntrl(int ch)

作用:判断字符是否为控制字符。若是,返回非零的值;否则,返回0

参数:ch为整型

printf("%d",iscntrl('\n'));

⑦isgraph(int ch)

作用:判断字符是否为图形字符(数字、大写字母、小写字母、标点字符)。若是,返回非零的值;否则,返回0

参数:ch为整型

⑧isspace(int ch)

作用:判断字符是否为空白间隔符(空格’ ‘、换页’\f’、换行’\n’、回车’\r’、水平制表’\t’、垂直制表’\v’)。若是,返回非零的值;否则,返回0

参数:ch为整型

/*
值得一提的是C语言在处理你输入的代码时
会忽略空白间隔符
包括现在写的注释也会被处理成空格

⑨isprint(int ch)

作用:判断字符是否为可打印字符(数字、字母、标点符号、空格)。若是,返回非零的值;否则,返回0

参数:ch为整型

⑩ispunct(int ch)

作用:判断字符是否为标点符号。若是,返回非零的值;否则,返回0

参数:ch为整型


# ?:运算符号

表达式?为真返回值:为假返回值

# switch

switch(integer-expression){// 整形
    case label1 : statement(s)
    case label2 : statement(s)
    default statement(s)
    }

注意每条选择必须加break

还可以使用枚举enum类型选择

# break 和 continue

break:跳出循环

continue:跳过这轮循环

# 输入输出到文件

# 输出到文件

#include<iostream>
#include<fstream>

int main() {
    using namespace std;

    char ch[60];
    int year;
    double a_price;
    double d_price;

    ofstream outFile;// 创建实例
    outFile.open("carinfo.txt");// 打开文件
    outFile<<"Year: "<<year<<endl;// 输出到文件

    outFile.close();
}

open()每一次运行的时候创建一个空白的carinfo.txt替换文件

# 读取文件

#include<iostream>
#include<fstream>
const int SIZE = 60;

int main() {
    using namespace std;
    char filename[SIZE];
    ifstream infile;
    cout << "Enter the name of data file: ";
    cin.getline(filename, SIZE);

    infile.open(filename);// 打开文件
    if (!infile.is_open()) // 如果没有成功打开
    {
        cout << "File could not be opened"<< filename << endl;
        exit(EXIT_FAILURE);
    }
    double value;
    double sum = 0;
    int counter = 0;

    infile >> value;
    while (infile.good())// 判断是否读取成功
    {
        ++counter;
        sum += value;
        infile >> value;
    }

    if (infile.eof())// 是否读到末尾
        cout << "End of file reached." << endl;
    else if (infile.fail())// 是否读取数据不匹配
        cout << "Input terminated by data mismatch.\n";
    else// 其他原因
        cout << "Input terminated for unknown reason." << endl;

    infile.close();// 关闭文件
}

# 函数

使用函数必须完成:

  • 函数定义
  • 函数原型
  • 调用函数

库函数是定义和编译好了的函数,头文件包含原型

#include<iostream>
void simple(void);// 函数的原型(声明)

int main() {
    using namespace std;
    simple();// 调用

    return 0;
}

void simple(void) {// 函数定义
    using namespace std;
    cout << "I'm but a simple function.\n";
}

# 函数和数组

#include<iostream>
const int ArSize = 8;
int main() {
    using namespace std;
    int cookies[ArSize] = {1,2,4,8,16,32,64,128};
    sum_arr(cookies,ArSize);// 注意是数组名和数组大小
    return 0;
}

int sum_arr(int arr[ArSize], int size) {
// 相当于 int sum_arr(int *arr int size) {
    int sum = 0;
    for (int i = 0; i < size; i++) {
        sum += arr[i];
    }
    return sum;
}

arr[ArSize]传参相当于指针传参

传入数组要明确指出数组元素个数

# 只读指针

如果只想只读就使用const chat* str,避免共用地址被修改的问题

指针和内容都是不可变的

# 返回字符串

返回字符串可以返回数组地址

# string对象

void display(const string* ar,int n) {
    for(int i = 0; i < n; i++) {
        cout << i+1 <<": "<<ar[i]<<endl;
    }
    display(list,SIZE);

# array对象

#include<iostream>
#include<array>

const int Seasons = 4;
std::array<std::string, Seasons> SeasonNames = {"Spring","Sunmmer","Fall","Winter"};
void fill(std::array<double, Seasons> *pa);
void show(std::array<double, Seasons> da);
int main() {

    std::array<double, Seasons> expenses;
    fill(&expenses);
    show(expenses);
    return 0;
}

void fill(std::array<double, Seasons> *pa) {
    using namespace std;
    for (int i = 0; i < Seasons; i++) {
        cout << "Enter" << SeasonNames[i] << "expenses" << endl;
        cin >> (*pa)[i];
    }
}

void show(std::array<double, Seasons> da) {
    using namespace std;
    double total = 0.0;
    for (int i = 0; i < Seasons; i++) {
        cout << SeasonNames[i] << " " << da[i] << endl;
        total += da[i];
    }
    cout << total << endl;
}


# 递归

包含函数自己的递归

一般需要一个条件判断语句终止

#include <iostream>
void countdown(int number);

int main() {
using namespace std;
countdown(4);

return 0;
}

void countdown(int number) {
    using namespace std;
    cout << "count down: " << number << endl;
    if (number > 0 )
        countdown(number - 1);
    cout << number << "kaboom" << endl;
}

# 函数指针

获取函数地址:函数名(不加括号就是地址)
区分函数的返回值函数名()

double pam(int)
double (*pf)(int)
// 当*pf指向pam,两条作用等同

一般用于函数内直接调用其他函数

#include <iostream>
double betsy(int lns) ;
double pam(int lns) ;
void estimate(int lines,double(*pf)(int));

int main() {
using namespace std;
    int code;
    cout << "How many lines of code do you need?";
    cin >> code;
    cout << "Here's Betsy's estimate:\n";
    estimate(code,betsy);// 传入besty函数
    cout << "Here's Pam's estimate:\n";
    estimate(code,pam);
    return code;

}

double betsy(int lns) {
    return 0.05 * lns;
}

double pam(int lns) {
    return 0.03 * lns + 0.0004 * lns * lns;
}

void estimate(int lines,double(*pf)(int)) {// 按地址读出来
    using namespace std;
    cout << lines << "lines will take" ;
    cout << (*pf)(lines) << "hours" << endl;
}

一个等式: **&pa == *pa == pa[0]

详细解释各种函数指针:

#include <iostream>

const double *f1(const double *ar, int n);

// const double* f1(const double ar[],int x);
// const double* f1(const double[],int n);
// const double* f1(const double*,int);

/*  四种函数原型都符合规定
 *  变量可以写别的名字,可以不写
 *  数组和地址可以互换
 *  只要确定函数名、返回值就行
 */

const double *f2(const double [], int n);

const double *f3(const double *, int n);

int main() {
    using namespace std;
    double av[3] = {1112.3, 12312.4, 123.7};

    const double * (*p1)(const double *ar, int n) = f1; //函数入口地址赋给函数指针
    auto p2 = f2; // 自动类型
    //const double* (*p2)(const double* ar,int n) = f2;等同

    cout << "Address value" << endl;
    cout << (*p1)(av, 3) << ":" << *(*p1)(av, 3) << endl; //f1(av,3):*(f1(av,3))____0x16d9d31b0:1112.3
    cout << p1(av, 3) << ":" << *p1(av, 3) << endl; //p1、*p1等价,仅限于函数指针
    cout << p2(av, 3) << ":" << *p2(av, 3) << endl;


    const double * (*pa[3])(const double *, int) = {f1, f2, f3}; //pa是三个元素的数组,内容都是函数指针
    auto pb = pa;
    //const double* (**pb)(const double*,int) = pa;等同
    cout << "Address value" << endl;
    for (int i = 0; i < 3; i++) {
        cout << pa[i](av, 3) << ":" << *pa[i](av, 3) << endl;
        cout << (*pa[i])(av, 3) << ":" << (*(*pa[i]))(av, 3) << endl; // 等效
    }
    cout << "Address value" << endl;
    for (int i = 0; i < 3; i++) {
        cout << pb[i](av, 3) << ":" << *pb[i](av, 3) << endl;
        cout << (*(pb[i]))(av, 3) << ":" << *((*(pb[i]))(av, 3)) << endl; // 等效
    }
    auto pc = &pa;
    //const double* (*(*pc)[3])(const double*,int) = &pa;等同
    cout << "Address value" << endl;
    cout << (*pc)[0](av, 3) << ":" << *(*pc)[0](av, 3) << endl;
    cout << (*((*pc)[0]))(av, 3) << ":" << *(*((*pc)[0]))(av, 3) << endl;
    const double * (*((*pd)[3]))(const double *, int) = &pa;
    const double *pdb = (*pd)[1](av, 3);
    cout << pdb << ":" << *pdb << endl;
    cout << (*(*pd)[2])(av, 3) << ":" << *(*(*pd)[2])(av, 3) << endl;
    return 0;
}

const double *f1(const double *ar, int n) {
    // const 保证只读,不修改地址和内容
    return ar; // ar = ar + 0 = &ar[0]
    // 返回类型是const double*
}

const double *f2(const double ar[], int n) {
    return ar + 1; // ar + 1 = &ar[1]
}

const double *f3(const double ar[], int n) {
    return ar + 2; // ar + 2 = &ar[2]
}

可以用auto typedef简化:typedef用法

# 内联函数

普通函数:跳转

内敛函数:复制并替换

特点:以空间换时间、不能递归

使用需要在声明和定义加上inline

#include <iostream>
inline double square(double x) {return x*x;}
int main() {
    using namespace std;
    double a, b;
    a = square(5.0);
    // double x = 5.0;
    // a = x * x;
    cout << a << endl;
    return 0;
}

# 引用变量

创建别名,内存指向同一个地方

int rats;
int & rodents = rats;// 必须初始化赋值,只能绑定一个内存空间

与指针区别:

int rats =101;
int & rodents = rats;
int * prats = &rats;

无法先声明再赋值

rodent = rat;//不允许

其与const指针更类似

# 函数传递

**按值传递:**创建副本传递

int main() {
    int times = 20;
    sneezy(times);
    return 0;
}
void sneezy(int x) {// 创建x变量。传递20给x
    ……
}

按引用传递:

int main() {
    int times = 20;
    sneezy(times);
    return 0;
}
void sneezy(int &x){// x是times别名
    ……
}

按指针传递:

int main() {
    int times = 20;
    sneezy(&times);
    return 0;
}
void sneezy(int *x){// x是time指针
    ……
}

比较:

#include <iostream>
void swapr(int &a, int &b);
void swapp(int* p, int* q);
void swapv(int a, int b);
int main() {
    using namespace std;
    int wallet1 = 100;
    int wallet2 = 350;
    cout <<"wallet1 = "<<wallet1<<" wallet2 = "<<wallet2<<endl;
    cout << "using references to swap contents:"<<endl;
    swapr(wallet1,wallet2);
    cout << "wallet1 = "<<wallet1<<" wallet2 = "<<wallet2<<endl;

    cout << "using pointers to swap contents:"<<endl;
    swapp(&wallet1,&wallet2);
    cout << "wallet1 = "<<wallet1<<" wallet2 = "<<wallet2<<endl;

    cout << "Trying to use passing by value:"<<endl;
    swapv(wallet1,wallet2);
    cout<<"wallet1 = "<<wallet1<<" wallet2 = "<<wallet2;
    return 0;
}

void swapr(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}
void swapp(int* p, int* q) {
    int temp = *p;
    *p = *q;
    *q = temp;
}
void swapv(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

指针在操作过程中需要*,引用不用

# 区分左值和右值

&可以取地址就是左值,不能就是右值

注意: 字符串可以取地址,是左值

引用必须是左值

# 临时变量

引用使用右值的时候,可以加const作为临时变量

cout << recube(10);
double recube(const double& ra){
	return ra*ra*ra;
}

实参类型不正确,使用const自动转换

int x = 2;
cout << recube(x);
double recube(const double& ra){
	return ra*ra*ra;
}

字符串取地址要用const修饰

const string& b = "abc";

在引用推荐尽可能使用const

double && rref = 6.0//C++11新特性:引用右值

避免返回临时变量的引用

// 错误示例
const free_throws & clone2(free_throws & ft){
	free_throws newguy;//创建临时变量的引用
	newguy = ft;
	return newguy;//返回临时变量引用,错误
}

函数调用结束会销毁临时变量,解决方法:返回给传入的引用

# 结构和引用

#include <iomanip>
#include <iostream>
#include <numeric>
#include <string>
struct free_throws{
    std::string name;
    int made;
    int attempts;
    float percent;
};
void set_pc(free_throws& ft);
void display(const free_throws& ft);
free_throws & accumulate(free_throws & target,const free_throws & source);
int main(){
    using namespace std;
    free_throws one = { "Ifelsa Branch", 13, 14 };
    free_throws two = { "Andor Knott", 10,16 };
    free_throws three ={ "Minnie Max",7,9 };
    free_throws four = { "Whily Looper", 5,9 };
    free_throws five = { "Long Long", 6,14 };
    free_throws team = {"Throwgoods", 0,0 };
    free_throws dup;
    set_pc(one);
    display(one);
    accumulate(team,one);
    display(team);
    display(accumulate(team,team));
    accumulate(accumulate(team,three),four);
    display(accumulate(team,five));
    dup = accumulate(team,five);
    display(team);
    display(dup);
    set_pc(four);
    accumulate(dup,five)=four;//返回的引用被four结构体赋值
    display(dup);
    
    return 0;
}

void set_pc(free_throws& ft) {//one别名
    if (ft.attempts != 0) {
        ft.percent = float(ft.made)/float(ft.attempts);
    }else {
            ft.percent = 0;
        }
    }
    void display(const free_throws& ft) {
        using namespace std;
        cout << "name: " << ft.name << endl;
        cout << "made: " << ft.made << endl;
        cout << "attempts: " << ft.attempts << endl;
        cout << "percent: " << ft.percent << endl;
    }
free_throws & accumulate(free_throws & target,const free_throws & source) {//返回值是引用
    target.attempts += source.attempts;
    target.made += source.made;
    set_pc(target);
    return target;
}

# 默认参数

在函数原型中说明默认参数

char * left(const char * str,int n =1);//,n默认为1

此时n可以不传

# 函数重载

void print(const char *str ,int width);
void print(double d,int width);
void print(long l,int width);

根据参数列表选择

# 函数模板

函数模板是泛型

void swapr(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}
void swapp(int* p, int* q) {
    int temp = *p;
    *p = *q;
    *q = temp;
}

函数遇到这种参数类型外其他一样,可以使用函数模板简化

template <typename AnyType>//声明模板
// typename(以及class)是参数类型 AnyType是类型名(可自定义)
void Swap(AnyType &a,AnyType &b) {
    AnyType temp;
    temp=a;
    a=b;
    b=temp; 
}

通常会放在头文件里

# 具体化

// 模板函数
template <typename T>
void Swap(T &,T &);
// 显示具体化的模板函数
template <> void Swap<job>(job &,job &);
template <> void Swap<>(job &,job &);//前job可省略
{
  ……
}

直接在特定某处写了个模板(类似直接定义模板,不走头文件的模板)

Swap(a,b);//隐式实例化
Swap<int>(a,b);//显式示例化,直接在前面的模板套上int

# decltype关键字

template<class T1,class T2>
void ft(T1 x,T2 y){
	//x+y:当T1+T2的时候,不知道结果的类型,使用decltype自动处理
	decltype(x+y) xpy = x+y;
}

# 名称空间和内存模型

# 单独编译

把一个程序文件拆分成多个文件:

  • 头文件:包含结构(struct)、类(class)、模板的声明;函数原型、#define、const、内联函数
  • 源文件:包含与结构有关的函数代码
  • 源代码:包含调用与结构相关函数的代码

#是预编译

#include<iostream>//系统提供,尖括号
#include"abc.h"//自己编写,引号

避免重复定义方法,如果定义只看第一次:

//corrdin.h
#ifndef CORRDIN_H_
#define CORRDIN_H_
	……
#endif

网站的管理员,似乎是个萌新🤔,CTBUer