C++ 基础速查笔记
更新中…
目录
1. 绪论
- C++ 最初由 Bjarne Stroustroup 于
1979
年在贝尔实验室开发 - C++ 是一种面向对象的语言,实现了继承、封装、多态等概念
1998
年,第一个 C++ 标准获得了 ISO 标准委员会的批准,俗称C++98
C++11
、C++14
、C++17
#include <iostream>
int main()
{
std::cout<< "Hello World!" << std::endl;
return 0;
}
2. C++ 程序结构
#include
:预处理器编译指令,在编译前运行< >
:包含标准头文件" "
:包含自定义头文件main()
:程序的主体std::count
:命名空间,即namespace
- C++ 区分大小写
- 注释会被编译器忽略
int main(int argc, char* argv[])
3. 变量与常量
3.1 变量
变量名规范
- 变量名可包含数字、字母、下划线
- 但不能以数字开头
- 变量名不能是保留的关键字
- 可在同一行初始化多个相同类型的变量
int first = 0, second = 0, third = 0;
命名约定
- 变量名小写字母开头
- 函数名等其他元素大写字母开头
- 驼峰命名法
常用变量类型
C++14
新增了用'
表示的组块分隔符chunking separator
,可以提高数字的可读性
int totalCash = 0;
bool isLampOn = false;
char userInput = 'Y';
short int gradesInMath = -5;
int moneyInBank = -7'0000;
long populationChange = -8'5000;
long long countryGDPChange = -700'0000;
unsigned short int numColorsInRainbow = 7;
unsigned int unmEggsInBasket = 24;
unsigned long numCarsInNewYork = 70'0000;
unsigned long long countryMedicareExpense = 7'0000'0000;
float pi = 3.14;
double morePrecisePi = 22.0 / 7;
sizeof 确定变量长度
cout << "Size of an int: " << sizeof(int);
列表初始化/缩窄转换
C++11
引入了列表初始化来禁止缩窄转换:
int largeNum = 700'0000;
short smallNum{largeNum};
auto 自动推断
C++11
或更高版本可不显式指定变量的类型,而使用关键字auto
:
auto coinFlippedHeads = true;
注意:如果将变量类型声明为
auto
,但不对其进行初始化,将出现编译错误
typedef 定义变量类型
使用关键字typedef
定义变量类型:
typedef unsigned int STRICTLY_POSITIVE_INTEGER;
STRICTLY_POSITIVE_INTEGER numEggsInBasket = 4532;
3.2 常量
在C++
中,常量可以是:
- 字面常量
- 使用关键字
const
声明的常量 - 使用关键字
constexpr
声明的表达式(C++11
新增) - 使用关键字
enum
声明的枚举常量 使用关键字#define
定义的常量(已废弃)
字面常量
字面常量可以是任何类型。从C++14
开始,还可以使用二进制字面常量:
int someNumber = 10;
int someNumber = 012; // 八进制
int someNumber = 0b1010; // 二进制
const 定义常量
使用关键字const
定义常量,常量定义后不可修改:
const double pi = 22.0 / 7;
constexpr 定义常量表达式
常量表达式提供了编译阶段优化的可能性。
只要编译器能够从常量表达式计算出常量,就会在编译阶段将其替换为常量,避免了在代码运行时进行计算。
const double GetPi()
{
return 22.0 / 7;
}
const double TwicePi()
{
return 2 * GetPi();
}
enum 枚举
可使用关键字enum
声明枚举,枚举由一组称为枚举量emumerator
的常量组成:
enum RainbowColors
{
Violet, // 0
Indigo, // 1
Blue, // 2
Green = 4, // 4, 显式初始化
Yellow, // 5
Orange = 1, // 1, 显式初始化
Red // 2
};
- 编译器将枚举量转换为整数,每个枚举量都比前一个大
1
- 如果没有指定起始值,编译器默认起始值为
0
- 可以通过显式初始化为每个枚举量指定值
4. 数组与字符串
4.1 静态数组
静态数组的长度在编译阶段就已确定,因此其占据的内存也是固定的。
编译器为静态数组预留的内存量为
sizeof(element-type)*length
const int ARRAY_LENGTH = 5;
int myNumbers[ARRAY_LENGTH] = {34, 21, -56, 5002, 1314};
int myNumbers[ARRAY_LENGTH] = {}; // {0, 0, 0, 0, 0}
int myNumbers[ARRAY_LENGTH] = {34, 21}; // {34, 21, 0, 0, 0,}
4.2 多维数组
int solarPanels[2][3] = {{0, 1, 2},
{3, 4, 5}};
4.3 动态数组
需要包含头文件
#include <vector>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> dynArray(3); // dynamic array of int
dynArray[0] = 365;
dynArray[1] = -421;
dynArray[2] = 789;
cout << "Number of integers in array: " << dynArray.size() << endl;
cout << "Enter another element to insert: ";
int newValue = 0;
cin >> newValue;
dynArray.push_back(newValue);
cout << "Number of integers in array: " << dynArray.size() << endl;
cout << "Last element in array: ";
cout << dynArray[dynArray.size() - 1] << endl;
return 0;
}
------
Number of integers in array: 3
Enter another element to insert: 4
Number of integers in array: 4
Last element in array: 4
4.4 C 风格字符串
- 最后一个字符为空字符
\0
,即终止空字符 - 数组中间插入
\0
不会改变数组的长度,只会导致字符串处理到这个位置结束
#include <iostream>
using namespace std;
int main()
{
char sayHello[] = {'H', 'e', 'l', 'l', 'o', '\0'};
cout << sayHello << endl;
cout << "Size of sayHello: " << sizeof(sayHello);
return 0;
}
------
Hello
Size of sayHello: 6
4.5 C++ 字符串 std::string
不同于字符数组(C 风格字符串实现),std::string
是动态的,在需要存储更多数据时其容量会增大。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string greetStr("Hello std::string!");
cout << greetStr << endl;
cout << "Enter a line of text:" << endl;
string firstLine;
getline(cin, firstLine);
cout << "Enter another:" << endl;
string secondLine;
getline(cin, secondLine);
cout << "Result of concatenation:" << endl;
string concatStr = firstLine + " " + secondLine;
cout << concatStr << endl;
cout << "Copy of concatenated string:" << endl;
string aCopy;
aCopy = concatStr;
cout << aCopy << endl;
cout << "Length of concat string: " << concatStr.length() << endl;
return 0;
}
------
Hello std::string!
Enter a line of text:
this is the first line
Enter another:
this is the second line
Result of concatenation:
this is the first line this is the second line
Copy of concatenated string:
this is the first line this is the second line
Length of concat string: 46
5. 语句与运算符
5.1 语句
当编译器注意到有两个相邻的字符串字面量后,会将其拼接成一个:
cout << "The first line of content"
"The second line of content"
"The third line of content"
<< endl;
5.2 前缀/后缀运算符
- 后缀运算符
num1++
先将右值赋给左值,再将右值递增或递减 - 前缀运算符
++num1
先将右值递增或递减,再将结果赋给左值 - 理论上,
++startValue
优于startValue++
,因为使用后缀运算符时,编译器需要临时存储初始值,以防需要将其赋给其他变量
int num1 = 101;
int num2 = num1++; // num1 = 102, num2 = 101
int num3 = ++num1; // num1 = 103, num3 = 103
5.3 逻辑运算符
- NOT:
!
- AND:
&&
- OR:
||
5.4 位运算符
- NOT:
~
- AND:
&
- OR:
|
- XOR:
^
- 左移:
<<
,相当于乘以2^n
- 右移:
>>
,相当于除以2^n
6. 控制程序流程
6.1 if else
if (condition)
{
do something...
}
else
{
do something else...
}
6.2 switch case
switch (expression)
{
case /* constant-expression */:
/* code */
break;
default:
break;
}
6.3 三目运算符
int max = (num1 > num2) ? num1 : num2;
6.4 while
while (/* condition */)
{
/* code */
}
6.5 do while
do
{
/* code */
} while (/* condition */);
6.6 for
for (size_t i = 0; i < count; i++)
{
/* code */
}
6.7 for range
for (VarType varName : sequence)
{
do something...
}
可以使用关键字auto
自动推断变量的类型:
for (auto anElement : elements)
6.8 continue 和 break
continue
:跳转到循环开头,跳过本次循环之后的代码,进入下一次循环break
:退出循环块,结束当前循环
7. 函数
7.1 函数原型与函数定义
- 函数原型:指出了函数的名称、接受的参数列表以及返回值的类型
- 函数定义:也即函数的实现代码
#include <iostream>
using namespace std;
const double Pi = 3.14159265;
// Function Declarations (Prototypes)
double Area(double radius);
double Circumference(double radius);
int main(int argc, char const *argv[])
{
cout << "Enter radius: ";
double radius = 0;
cin >> radius;
// Call function "Area"
cout << "Area is: " << Area(radius) << endl;
// Call function "Circumference"
cout << "Circumference is: " << Circumference(radius) << endl;
return 0;
}
// Function definitions (Implementations)
double Area(double radius)
{
return Pi * radius * radius;
}
double Circumference(double radius)
{
return 2 * Pi * radius;
}
------
Enter radius: 10
Area is: 314.159
Circumference is: 62.8319
在函数原型中可以添加函数参数的默认值:
double Area(double radius, double Pi = 3.14);
7.2 函数重载
// for circle
double Area(double radius)
{
return Pi * radius * radius;
}
// overloaded for cylinder
double Area(double radius, double height)
{
// reuse the area of circle
return 2 * Area(radius) + 2 * Pi * radius * height;
}
7.3 按引用传递参数
当希望函数修改的变量在其外部中也可用时,可将形参的类型声明为引用:
#include <iostream>
using namespace std;
const double Pi = 3.14159265;
// output parameter result by reference
void Area(double radius, double &result)
{
result = Pi * radius * radius;
}
int main(int argc, char const *argv[])
{
cout << "Enter radius: ";
double radius = 0;
cin >> radius;
double areaFetched = 0;
Area(radius, areaFetched);
cout << "The area is: " << areaFetched << endl;
return 0;
}
------
Enter radius: 10
The area is: 314.159
7.4 函数调用
函数调用意味着:
- 微处理器跳转到属于被调用函数的下一条指令处执行,对应
CALL
指令 - 执行完函数的指令后,将返回最初离开的地方,对应
RET
语句
inline 内联函数
常规函数调用被转换为CALL
指令,这会导致栈操作、微处理器跳转到函数处执行等。但如果函数非常简单:
double GetPi()
{
return 3.14159;
}
相对于实际执行GetPi()
的时间,执行函数调用的开销可能非常高。使用关键字inline
可以让函数在被调用时就地展开:
inline double GetPi()
{
return 3.14159;
}
仅当函数非常简单,需要降低开销时,才应使用
inline
关键字
auto 自动推断返回类型
从C++14
起,auto
也适用于函数返回类型的自动推断:
auto Area(double radius)
{
return Pi * radius * radius;
}
lambda 函数
语法如下,后续会详细介绍:
[optional parameters](parameter list){ statements; }
8. 指针和引用
8.1 什么是指针
- 指针是存储内存地址的变量
- 指针包含的值被解读为内存地址
- 内存单元地址通常使用十六进制表示,如
0x60fe80
- 使用引用运算符
&
获取变量的地址 - 使用解除引用运算符
*
访问指针指向的数据 32
位系统,指针变量为4
字节,64
位系统为8
字节
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
int dogsAge = 30;
cout << "Initialize dogsAge = " << dogsAge << endl;
int *pointsToAnAge = &dogsAge;
cout << "pointsToAnAge points to dogsAge" << endl;
cout << "Enter an age for your dog: ";
// store input at the memory pointed to by pointsToAnAge
cin >> *pointsToAnAge;
// Displaying the address where age is stored
cout << "Integer stored at " << hex << pointsToAnAge << endl;
cout << "Integer dogsAge = " << dec << dogsAge << endl;
return 0;
}
------
Initialize dogsAge = 30
pointsToAnAge points to dogsAge
Enter an age for your dog: 14
Integer stored at 0x60fe88
Integer dogsAge = 14
8.2 动态内存分配
new 和 delete 运算符
使用new
来分配新的内存块,最终都需使用对应的delete
进行释放:
int *pNum = new int; // get a pointer to an integer
int *pNums = new int[10]; // pointer to a block of 10 integers
delete pNum;
delete[] pNums;
对于使用
new[...]
分配的内存块,需要使用delete[]
进行释放
不再使用分配的内存后,如果不释放它们,这些内存仍被预留并分配给应用程序,这将减少系统内存量,甚至降低应用程序的执行速度,即内存泄露。
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
// Request for memory space for an int
int *pointsToAnAge = new int;
// Use the allocated memory to store a number
cout << "Enter your dog's age: ";
cin >> *pointsToAnAge;
// Use indirection operator* to access value
cout << "Age " << *pointsToAnAge << " is stored at " << hex << pointsToAnAge << endl;
// Release memory
delete pointsToAnAge;
return 0;
}
------
Enter your dog's age: 14
Age 14 is stored at 0xf518c0
而对于使用new[...]
分配的内存,应使用delete[]
来释放:
int *myNumbers = new int[numEntries];
...
// de-allocate before existing
delete[] myNumbers;
指针递增或递减
将指针递增或递减时,其包含的地址将增加或减少sizeof(Type)
。
例如声明了如下指针:
Type *pType = Address;
则执行++pType
后,pType
将指向Address + sizeof(Type)
。
将
++
用于该指针,相当于告诉编译器,希望它指向下一个int
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
cout << "How many integers you wish to enter? ";
int numEntries = 0;
cin >> numEntries;
int *pointsToInts = new int[numEntries];
cout << "Allocated for " << numEntries << " integers" << endl;
for (int counter = 0; counter < numEntries; ++counter)
{
cout << "Enter number " << counter << ": ";
cin >> *(pointsToInts + counter);
}
cout << "Displaying all numbers entered: " << endl;
for (int counter = 0; counter < numEntries; ++counter)
{
cout << *(pointsToInts++) << " ";
}
cout << endl;
// return pointer to initial position
pointsToInts -= numEntries;
cout << *pointsToInts;
// done with using memory? release
delete[] pointsToInts;
return 0;
}
------
How many integers you wish to enter? 5
Allocated for 5 integers
Enter number 0: 10
Enter number 1: 29
Enter number 2: 35
Enter number 3: -3
Enter number 4: 918
Displaying all numbers entered:
10 29 35 -3 918
10