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
# 数组
# 三要素
- 每个元素的类型
- 数组名
- 元素数量
# 声明
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;
}
# 创建动态结构
-
创建结构
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的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(×);
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