C++语法学习(一)

C++语法学习(一)


C++基础语法

1. 基本数据类型

1.1 算数类型
  1. 类型
image-20240306195216531
image-20240312204156143
  1. 可寻址的最小内存块成为“字节(byte)”,存储的基本单元成为“字(word)”,1 byte = 8 bit。
  2. 带符号类型(可以表示正数、负数或0):int、short、long、long long。
  3. 无符号类型(仅能表示大于等于0的值):(unsigned)int、long···。

字符型被分为了三种:char、signed char和unsigned char。

  1. 关键字auto自动推断类型:使用 auto 时必须对变量进行初始化。
1.2 类型转换
  1. 当一个算术表达式中既有无符号又有int值时,int值就会转换成无符号数。
1
2
3
4
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl; // -84
std::cout << u + i << std::endl; // 4294967264
1.3 字面值常量
  1. 以0开头的整数代表八进制数,以0x或0X开头的代表十六进制数。
  2. 字符和字符串字面值:由单引号括起来的一个字符称为char型字面值,双引号括起来的零个或多个字符则构成字符串字面值。
1
2
'a'	// 字符字面值
"Hello World!" // 字符串字面值
image-20240312170711902
  • 以U为后缀的十进制数、八进制数或十六进制数都将从 unsigned int、unsigned long和unsigned long long 中选择能匹配的空间最小的一个作为其数据类型。

  • 如果后缀中有L,则字面值的类型至少是long;

  • 如果后缀中有LL,则字面值的类型将是long long 和 unsigned long long中的一种。

2. 常量

  1. 字面常量:字面常量可以是任何类型,布尔型、整型、字符串等。
  2. 关键字const将变量声明为常量。
  3. constexpr 定义常量表达式。
1
2
//通过关键字constexpr,可让常量声明像函数:
constexpr double GetPi() {return 22.0 / 7;}
  1. 关键字 enum 声明枚举。枚举由一组称为枚举量(emumerator)的常量组成。
1
2
3
4
5
6
7
8
9
10
11
12
enum RainbowColors{
Violet = 0,
Indigo,
Blue,
Green,
Yellow,
Orange,
Red
};

// 声明一个变量,用于存储彩虹的颜色
RainbowColors MyFavoriteColor = Blue; // Initial value
  1. 使用#define定义常量(使用#define 定义常量的做法已被摒弃,因此不应采用这种做法。)
  2. 不能用作常量或变量名的关键字

image-20240312224513192

3. 数组

  1. 声明和初始化静态数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 一维静态数组

int myArray[5] = {1, 2, 3, 4, 5}; // 所有元素被显式初始化。
char myCharArray[4] = {'A', 'B', 'C', 'D'}; // 对于字符数组也是同样的方式。
int myArray[5] = {1, 2, 3}; // 数组的最后两个元素将自动初始化为0。
int myArray[] = {1, 2, 3, 4, 5}; // 编译器自动推导数组大小为5。
int myArray[5] = {0}; // 所有元素被初始化为0。
int myArray[5] = { [0] = 1, [2] = 3, [4] = 5 }; // 初始化索引为0, 2, 4的元素,其余元素为0。

// 二维静态数组

int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};

// matrix中每行的第三个元素将自动初始化为0。
int matrix[2][3] = {
{1, 2},
{4, 5}
};

// 自动推导出matrix有两行。
int matrix[][3] = {
{1, 2, 3},
{4, 5, 6}
};


int matrix[2][3] = {{0}};

int matrix[2][3];
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
matrix[i][j] = i + j; // 根据某种规则赋值
}
}
  1. 动态数组 vectorvector<int> dynArray (3)

4. 运算符

  1. 左值和右值:左值通常是内存单元,右值可以是内存单元的内容。int daysInYear = 365daysInYear(左值),365(右值)
  2. 运算符
  • 加法运算符(+)、减法运算符(−)、乘法运算符(*)、除法运算符(/)和求模运算符(%)
1
2
3
4
5
6
7
int num1 = 22;
int num2 = 5;
int addNums = num1 + num2; // 27
int subtractNums = num1 – num2; // 17
int multiplyNums = num1 * num2; // 110
int divideNums = num1 / num2; // 4
int moduloNums = num1 % num2; // 2
  • 递增运算符(++)和递减运算符(−−)
1
2
3
4
5
int num1 = 101;
int num2 = num1++; // Postfix increment operator 后缀递增
int num2 = ++num1; // Prefix increment operator 前缀递增
int num2 = num1--; // Postfix decrement operator
int num2 = --num1; // Prefix decrement operator

使用后缀运算符时,先将右值赋给左值,再将右值递增或递减。这意味着在上述所有使用后缀运算符的代码中,num2 都为num1 的旧值(执行递增或递减前的值)。前缀运算符的行为完全相反,即先将右值递增或递减,再将结果赋给左值。在所有使用后缀运算符的代码中,num2 的值都与num1 的值相同。程序清单5.2 演示了将前缀和后缀递增和递减运算符用于一个int 变量的结果。

  • 相等运算符(==)和不等运算符(!=)
1
2
3
4
5
int personAge = 20;
bool checkEquality = (personAge == 20); // true
bool checkInequality = (personAge != 100); // true
bool checkEqualityAgain = (personAge == 200); // false
bool checkInequalityAgain = (personAge != 20); // false
  • 关系运算符

image-20240314103455592

  • 逻辑运算NOT、AND、OR 和XOR
运算符操作数1操作数1结果
NOTfalsetrue
NOTtruefalse
ANDfalsefalsefalse
ANDtruefalsefalse
ANDfalsetruefalse
ANDtruetruetrue
ORfalsefalsefalse
ORtruefalsetrue
ORfalsetrueture
ORtruetruetrue
XORfalsefalsefalse
XORtruefalsetrue
XORfalsetruetrue
XORtruetruefalse
  • 按位运算符NOT(~)、AND(&)、OR(|)和XOR(^)
  • 按位右移运算符(>>)和左移运算符(<<) 移位运算符将整个位序列向左或向右移动,其用途之一是将数据乘以或除以 \(2^n\)
1
2
3
4
5
// 将变量乘以2
int doubledValue = num << 1;

// 将变量除以2
int doubledValue = num >> 1;
  • 运算符优先级

image-20240314130536132

5. 流程控制语句

  1. 三目运算符:(conditional expression evaluated to bool) ? expression1 if true : expression2 if false;
  2. 基于范围的for 循环。
1
2
3
4
5
6
7
for (VarType varName : sequence){
// Use varName that contains an element from sequence
}

// 使用关键字 auto 来自动推断变量的类型,对任何类型的数组elements进行处理
for (auto anElement : elements) // range based for
cout << "Array elements are " << anElement << endl;

6. 函数定义与调用

  1. 函数原型:返回值类型 函数名(函数参数(可选):参数列表由参数类型和参数名组成,当有多个参数时,使用逗号分隔)
1
double Area(double radius);
  1. 如果函数声明中包含形参(parameter),调用函数时必须提供实参(argument),它们是函数的形参列表要求的值。
  2. 可以给多个参数指定默认值,但这些参数必须位于参数列表的末尾。
  3. 函数重载:名称和返回类型相同,但参数不同的函数被称为重载函数。
  4. 将数组传递给函数
1
2
3
4
5
// 显示一个整数的函数
void DisplayInteger(int Number);

// 显示整型数组的函数的原型
void DisplayIntegers(int[] numbers, int Length);
  1. 按引用传递参数:void Area(double radius, double& result)
  2. 内联函数:inline
1
2
3
inline double GetPi(){
return 3.14159;
}
  1. 自动推断返回类型: 关键字 auto
1
2
3
4
// 编译器将根据return 语句中使用double 变量的表达式来推断返回类型
auto Area(double radius){
return Pi * radius * radius;
}
  1. lambda 函数:[optional parameters](parameter list){ statements; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

void DisplayNums(vector<int>& dynArray) {
for_each(dynArray.begin(), dynArray.end(),
[](int element) { cout << element << " ";} // lambda
);
cout << endl;
}

int main() {
vector<int> myNums;
myNums.push_back(501);
myNums.push_back(-1);
myNums.push_back(25);
myNums.push_back(-35);

DisplayNums(myNums);

cout << "Sorting them in descending order" << endl;

sort(myNums.begin(), myNums.end(),
[](int num1, int num2) { return (num2 < num1); } // lambda
);

DisplayNums(myNums);

return 0;
}

7. 指针

7.1指针
  1. 指针是存储内存地址的变量。就像int 变量用于存储整数值一样,指针变量用于存储内存地址。
image-20240316141545935
  1. 声明指针:通常将指针声明为指向特定的类型(int –> 整数,内存块 –> void)
1
2
3
4
5
6
7
// 声明指针
PointedType * PointerVariableName;

// 初始化指针, NULL 是一个可以检查的值,且不会是内存地址
PointedType * PointerVariableName = NULL;

int *pointsToInt = NULL;
  1. 使用引用运算符(&)获取变量的地址,引用运算符(&)也叫地址运算符。
  2. 使用指针存储地址。
1
2
3
4
5
// 将变量的地址存储到一个指针中,需要声明一个同样类型的指针,并使用引用运算符(&)将其初始化为该变量的地址
Type* Pointer = &Variable;

int age = 30;
int* pointsToInt = &age;
  1. 使用解除引用运算符(*)访问指向的数据,解除引用运算符(*)也叫间接运算符。
  2. 指针大小:sizeof(*type),不管指针指向的内存单元是1字节还是8字节,存储指针所需要的内存量都相同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

using namespace std;

int main(){

cout << "sizeof fundamental types -" << endl;
cout << "sizeof(char) = " << sizeof(char) << endl;
cout << "sizeof(int) = " << sizeof(int) << endl;
cout << "sizeof(double) = " << sizeof(double) << endl;

cout << "sizeof pointers to fundamental types -" << endl;
cout << "sizeof(char*) = " << sizeof(char*) << endl;
cout << "sizeof(int*) = " << sizeof(int*) << endl;
cout << "sizeof(double*) = " << sizeof(double*) << endl;

return 0;
}

/*
sizeof fundamental types -
sizeof(char) = 1
sizeof(int) = 4
sizeof(double) = 8
sizeof pointers to fundamental types -
sizeof(char*) = 8
sizeof(int*) = 8
sizeof(double*) = 8
*/
7.2 动态内存分配
  1. 使用new动态地分配内存。
1
2
3
4
5
6
7
8
// 使用new 时,需要指定要为哪种数据类型分配内存
Type& Pointer = new Type;

// 需要为多个元素分配内存时,还可指定要为多少个元素分配内存
Type* Pointer = new Type[numElements];

int* pointToAnInt = new int;
int* pointToNums = new int[10];
  1. 使用delete动态地释放内存。
1
2
3
4
5
6
7
// 单个元素
Type* Pointer = new Type; // allocate memory
delete Pointer; // release memory allocated above

// 多个元素
Type* Pointer = new Type[numElements]; // allocate a block
delete[] Pointer; // release block allocated above
  • 不再使用分配的内存后,如果不释放它们,这些内存仍被预留并分配给您的应用程序。这将减少可供其他应用程序使用的系统内存量,甚至降低您的应用程序的执行速度。这被称为内存泄露,应不惜一切代价避免这种情况发生。
  • 不能将运算符delete 用于任何包含地址的指针,而只能用于new 返回的且未使用delete释放的指针。
  1. 关键字const用于指针(const指针)
  • 指针包含的地址是常量,不能修改,但可修改指针指向的数据
1
2
3
4
5
6
int daysInMonth = 30;
int* const pDaysInMonth = &daysInMonth;
*pDaysInMonth = 31; // OK! Data pointed to can be changed

int daysInLunarMonth = 28;
pDaysInMonth = &daysInLunarMonth; // Not OK! Cannot change address!
  • 指针指向的数据为常量,不能修改,但可以修改指针包含的地址,即指针可以指向其他地方
1
2
3
4
5
6
7
int hoursInDay = 24;
const int* pointsToInt = &hoursInDay;
int monthsInYear = 12;

pointsToInt = &monthsInYear; // OK!
*pointsToInt = 13; // Not OK! Cannot change data being pointed to
int* newPointer = pointsToInt; // Not OK! Cannot assign const to non-const
  • 指针包含的地址以及它指向的值都是常量,不能修改
1
2
3
4
5
6
int hoursInDay = 24;
const int* const pHoursInDay = &hoursInDay;

*pHoursInDay = 25; // Not OK! Cannot change data being pointed to
int daysInMonth = 30;
pHoursInDay = &daysInMonth; // Not OK! Cannot change address
7.3 常见指针错误
  1. 内存泄露:使用 new 动态分配的内存不再需要后,没有使用 delete 释放。
  2. 指针指向无效的内存单元:使用 * 对指针解引用未指向有效内存单元。
  3. 悬浮指针:使用 delete 释放指针后,任何有效指针都将无效,不应再使用。
  4. 检查使用new 发出的分配请求是否得到满足:1)使用异常,2)

8. 引用

  1. 引用是变量的别名。声明引用时,需要将其初始化为一个变量,因此引用只是另一种访问相应变量存储的数据的方式。
  2. 声明引用,使用引用运算符(&)。

VarType original = Value; VarType& ReferenceVariable = original;


C++语法学习(一)
http://seulqxq.top/posts/61084/
作者
SeulQxQ
发布于
2024年3月24日
许可协议