C++ 基础速查笔记

更新中…

目录

1. 绪论

  • C++ 最初由 Bjarne Stroustroup1979年在贝尔实验室开发
  • C++ 是一种面向对象的语言,实现了继承、封装、多态等概念
  • 1998年,第一个 C++ 标准获得了 ISO 标准委员会的批准,俗称C++98
  • C++11C++14C++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
将关键字 const 用于指针