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 bytes2 bytes4 bytes8 bytesMax values21474836473276721474836479223372036854775807*/确定常量的类型
cout << "year = " << 1492 << "\n";// 默认int存储1492char:特殊的整型
# 字符和字符串
'a'是字符
"a"是字符串
# 布尔类型
布尔转为整型
int ans = true; // 赋值为1int ans = true; // 赋值为1整型转为布尔
bool start = -100;// truebool 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; // intauto a = 1.0; // doubleautp y = 1.3e12L; // long double# 数组
# 三要素
- 每个元素的类型
- 数组名
- 元素数量
# 声明
short mouth [12];其中12元素数量必须已知,不可为变量(但是可以const int Size声明常量)
# 初始化规则
只能在定义数组的时候初始化,可以少于数组数目
int cards[4] = {3,6,8}; // 允许,序号3元素为0int 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;}# 创建动态结构
-
创建结构
struct things{int good;int bad;}; -
访问成员
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的ifor (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)
作用:将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(×); 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"//自己编写,引号避免重复定义方法,如果定义只看第一次:
#ifndef CORRDIN_H_#define CORRDIN_H_ ……#endif部分信息可能已经过时