C++学习笔记

1、C++编译过程
1.1、预处理,编译器将C++代码中的宏、引用等预处理指定进行展开,生成.i或.ii文件;
1.2、编译,编译器将展开后的文件进行编译生成汇编文件.s;
1.3、汇编,汇编器将汇编文件汇编生成链接文件.o或.obj;
1.4、链接,链接器将链接文件与库文件或第三方文件链接生成二进制文件,即可执行文件;
1.5、第一个C++程序

1
2
3
4
5
6
7
8
#include 
 
using namespace std;
 
int main(){
    cout << "Hello Cpp!!" << endl;
    return 0;
}

2、变量名三条定律
2.1、变量名只能是下划线、字母、数字;
2.2、首字母只能是下划线、字母;
2.3、不能是保留字/关键字;

3、C++常用数据类型
3.1、int –> 32位 -2147483648~+2147483647;
3.2、short int –> 16位 -32768~+32767;
3.3、long int –> 32位 -2147483648~+2147483647;
3.4、long long int –> 64位 -9223372036854775808 ~ +9223372036854775807;
3.5、float 32位 –> -3.4E-38~+3.4E+38;
3.6、double 64位 –> -1.7E-308~+1.7E+308;
3.7、char 8位 –> -128~+127;
3.8、关于精度的一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include 
#include 
 
using namespace std;
 
int main(){
    int i = 1234567890;
    float f = 1234567890123456789;
    double d = 1234567890123456789;
    long double ld = 1234567890123456789;
    cout << setprecision(20);
    cout << i << "\n" << f << "\n" << d << "\n" << ld << endl;
    return 0;
}

1234567890
1234567939550609408
1234567890123456768
1234567890123456789
Program ended with exit code: 0

4、经典冒泡排序C++实现

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
#include 
 
using namespace std;
 
int main()
{
    // 数组、数组长度、循环次数
    int array[] = {128, 1, 11, 3, 33, 71, 2, 31, 4, 25, 61};
    int len = sizeof(array) / sizeof(array[0]);
    int loop_count = len - 1;
    // 冒泡次数循环
    for (int i = 0; i < loop_count; i++){
        // 单次冒泡比较循环
        for (int j = 0; j < loop_count - i; j++){ if (array[j] > array[j+1]){
                array[j] = array[j] + array[j+1];
                array[j+1] = array[j] - array[j+1];
                array[j] = array[j] - array[j+1];
            }
        }
    }
    for (int i = 0; i < len; i++){
        cout << array[i] << endl;
    }
    return 0;
}
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 
 
using namespace std;
 
int main()
{
    // 数组、数组长度、循环次数(最后一个数不需要比较)
    int array[] = {2, 1, 4, 3, 6, 5, 8, 7, 10, 9};
    int len = sizeof(array) / sizeof(array[0]);
    int loop_count = len - 1;
    for (int i = 0; i < loop_count; i++){
        // 调换前假设当前第一个为最小数
        int min_index = i;
        // 从第1个开始循环,可减少一次循环
        for (int j = i + 1; j < len; j++){
            if (array[j] < array[min_index]){
                min_index = j;
            }
        }
        // 如果第一个为最小数,不交换
        if (i != min_index){
            array[i] = array[i] + array[min_index];
            array[min_index] = array[i] - array[min_index];
            array[i] = array[i] - array[min_index];
        }
    }
    // 重新打印数组中的值(排序后)
    for (int i = 0; i < len; i++){
        cout << array[i] << " ";
    }
    return 0;
}


5、二维数组的基本使用

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 
 
using namespace std;
 
int main()
{
    string students[] = {"S1", "S2", "S3"};
    string courses[] = {"语文", "数学", "英语"};
    const int s_len = 3;
    const int c_len = 3;
    int stu_cou[s_len][c_len];
    for (int i = 0; i < s_len; i++){
        for (int j = 0; j < c_len; j++){
            cout << "请输入" << students[i] << "的" << courses[j] << "成绩:"; cin >> stu_cou[i][j];
        }
    }
    for (int i = 0; i < c_len; i++){
        cout << '\t' << courses[i];
    }
    cout << endl;
    for (int i = 0; i < s_len; i++){
        cout << students[i];
        for (int j = 0; j < c_len; j++){
            cout << '\t' << stu_cou[i][j];
        }
        cout << endl;
    }
    return 0;
}

输出结果:
请输入S1的语文成绩:11
请输入S1的数学成绩:12
请输入S1的英语成绩:13
请输入S2的语文成绩:21
请输入S2的数学成绩:22
请输入S2的英语成绩:23
请输入S3的语文成绩:31
请输入S3的数学成绩:32
请输入S3的英语成绩:33
语文 数学 英语
S1 11 12 13
S2 21 22 23
S3 31 32 33

Process returned 0 (0x0) execution time : 12.522 s
Press any key to continue.

6、指针的两种解读方式
// 一个指向int值的指针ptr,重点在指向值为int型
1、int *ptr = nullptr;
// 一个int类型的指针ptr,重点在该变量为一个指针
2、int* ptr = nullptr;

7、引用reference
引用可以理解为对指针的封装,比指针原始的使用更加效率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include 
 
using namespace std;
 
int main()
{
    // 指针指向另一个变量
    int num1 = 10;
    int *ptr_num1 = &num1;
    cout << num1 << '\t' << *ptr_num1 << endl;
 
    // 引用指向另一个变量
    int num2 = 10;
    int &ref_num2 = num2;
    cout << num2 << '\t' << ref_num2 << endl;
    return 0;
}

8、数组与指针的相互作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include 
 
using namespace std;
 
int main()
{
    int arr[] = {1, 2, 3, 4, 5};
    // ptr_arr为指向数组的指针,可代替数组变量操作数组
    int *ptr_arr = arr;
    ptr_arr[0] = 10;
    cout << arr[0] << endl;
    // 数组变量代表的是数组本身,但指针本质只是地址
    cout << sizeof(arr) << '\t' << sizeof(ptr_arr) << endl;
    // 指针的基本运算
    int *ptr = &arr[2];
    ptr += 1;  // 自增或自减根据类型平衡
    cout << *ptr << endl;
    return 0;
}

输出结果:
10
20 4
4

Process returned 0 (0x0) execution time : 0.035 s
Press any key to continue.

9、程序的内存分配
9.1、栈区(stack)
**由编译器自动分配释放,一般存放函数的参数值、局部变量值等;
**操作方式类似数据结构中的栈(先进后出)
9.2、堆区(heap)
**一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收;
**注意:与数据结构中的堆是两回事,分配方式类似链表;
9.3、全局区(静态区staic)
**全局变量和静态变量是存储在一起的
**程序结束后由系统释放
9.4、文字常量区
**常量字符串就放在这里,程序结束由系统释放
9.5、程序代码区
**存放函数体的二进制代码

10、数组的参数传递

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include 
 
using namespace std;
 
/**
 打印一维数组
 
 @param int 数组名称
 @param int 数组长度
 */
void show(int[], int);
 
/**
 二维数组的打印(注意:第二个维度的数组长度必须指定!!)
 
 @param int 数组名称
 @param int 数组长度
 */
void show(int[][5], int);
 
/**
 等价于void show(int[][5], int);
 
 @param int 数组名称
 @param int 数组长度
 */
void show(int(*)[5], int);
int main(){
    int array1[] = {1, 2, 3, 4, 5};
    show(array1, 5);
    int array2[][5] = {
        {11, 12, 13, 14, 15},
        {21, 22, 23, 24, 25},
        {31, 32, 33, 34, 35}
    };
    show(array2, 3);
    return 0;
}
/**
 打印一维数组
 
 @param array 数组名称
 @param length 数组长度
 */
void show(int array[], int length){
    for (int i = 0; i < length; i++) {
        cout << array[i] << '\t';
    }
    cout << endl;
}
 
/**
 二维数组的打印(注意:第二个维度的数组长度必须指定!!)
 
 @param array 数组名称
 @param length 数组长度
 */
void show(int (*array)[5], int length){
    for (int i = 0; i < length; i++) {
        for (int j = 0; j < 5; j++) {
            cout << array[i][j] << '\t';
        }
        cout << endl;
    }
}

输出结果:
1 2 3 4 5
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
Program ended with exit code: 0

11、函数指针的基本用法

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include 
 
using namespace std;
 
int sum(int, int);
int mut(int, int);
int calc(int, int, int(*)(int, int));
int main(){
    // 直接使用函数名做为参数
    cout << "2 + 4 = " << calc(2, 4, sum) << endl;
    cout << "2 * 4 = " << calc(2, 4, mut) << endl;
    // 函数指针的声明方式:int(*ptr_name)(int, int)
    int (*calc_ptr)(int, int);
    // C++11及以后的版本可以使用auto ptr_name = function_name;
    auto ptr_sum = sum;
    int num1, num2;
    char calc_char;
    cout << "请输入需要计算的两个数与计算符(如:1 + 1):"; cin >> num1 >> calc_char >> num2;
    switch (calc_char) {
        case '+':
            calc_ptr = sum;
            break;
        case '*':
            calc_ptr = mut;
            break;
        default:
            calc_ptr = NULL;
            cout << "抱歉,您输入的计算符当前暂不支持" << endl;
            break;
    }
    if (calc_ptr != NULL){
        int res = calc(num1, num2, calc_ptr);
        cout << num1 << " " << calc_char << " " << num2 << " = " << res << endl;
        int res_sum = calc(num1, num2, ptr_sum);
        cout << num1 << " + " << num2 << " = " << res_sum << endl;
    }
    return 0;
}
/** 加法运算 */
int sum(int a, int b){
    return a + b;
}
/** 乘法运算 */
int mut(int a, int b){
    return a * b;
}
 
/**
 计算方法
 
 @param a 第一个运算数
 @param b 第二个运算数
 @param func 运算方法(加法或乘法)
 @return 运算结果
 */
int calc(int a, int b, int (*func)(int, int)){
    return func(a, b);
}

运行结果:
2 + 4 = 6
2 * 4 = 8
请输入需要计算的两个数与计算符(如:1 + 1):4 * 9
4 + 9 = 13
4 * 9 = 36
Program ended with exit code: 0

12、函数参数传递的实质(基本类型、指针、引用)

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
#include 
 
using namespace std;
void swap1(int, int);
void swap2(int *, int *);
void swap3(int &, int &);
int main(){
    int num1 = 10, num2 = 20;
    swap1(num1, num2);
    cout << "执行swap1后:" << num1 << '\t' << num2 << endl;
    swap2(&num1, &num2);
    cout << "执行swap2后:" << num1 << '\t' << num2 << endl;
    swap3(num1, num2);
    cout << "执行swap3后:" << num1 << '\t' << num2 << endl;
    return 0;
}
// 参数传递的是副本,对形参的修改不影响原值
void swap1(int num1, int num2){
    int temp = num1;
    num1 = num2;
    num2 = temp;
}
// 参数传递原始数据的指针,对指针操作直接作用原值
void swap2(int *num1, int *num2){
    int temp = *num1;
    *num1 = *num2;
    *num2 = temp;
}
// 参数传递原始数据的引用,对形参的操作直接作用原值,引用实质上是指针的封装
void swap3(int &num1, int &num2){
    int temp = num1;
    num1 = num2;
    num2 = temp;
}

运行结果:
执行swap1后:10 20
执行swap2后:20 10
执行swap3后:10 20
Program ended with exit code: 0

13、如果函数返回值为引用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include 
using namespace std;
/**
 返回类型为引用的函数实现
 @param num 引用参数
 @return 返回引用参数
 */
int &ref(int &num){
    num++;
    return num;
}
int main(){
    int num = 2;
    // 返回结果赋值给result1
    int result1 = ref(num);
    // 返回结果被result2引用
    int &result2 = ref(num);
    // 返回结果(引用)被赋值!!!引用返回结果的变量值都会被改变
    ref(num) = 10;
    cout << result1 << '\t' << result2 << endl;
}

运行结果:
3 10
Program ended with exit code: 0

14、函数重载时引用的重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include 
 
using namespace std;
 
void func(int num){
    cout << 1 << num << endl;
}
void func(int &num){
    cout << 2 << num << endl;
}
 
int main(){
    int num = 10;
    func(num);
    cout << "Hello Cpp!!!" << endl;
    return 0;
}

以上代码在编译时会报错:error: call of overloaded ‘func(int&)’ is ambiguous|
如果不调用不会报错,能正常编译,调用时则不行,原因是编译器无法区分到底该调用哪个函数,所以函数在重载时不能重载“引用”属性;

15、模板函数实例

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
38
39
40
41
42
43
44
45
#include <iostream>
 
using namespace std;
 
/**
 模板函数实现排序
 @param T 数组类型
 @param int 数组长度
 @return 实现数据内部排序,无返回值
 */
template <typename T> void Sort(T[],int);
/**
 模板函数实现输出
 @param T 数组类型
 @param int 数组长度
 @return 输出数组中元素,无返回值
 */
template <typename T> void Show(T[],int);
int main(){
    int array1[] = {2, 1, 4, 3, 6, 5};
    double array2[] = {2.2, 1.1, 4.4, 3.3, 6.6, 5.5};
    Sort(array1, 5);
    Sort(array2, 6);
    Show(array1, 5);
    Show(array2, 6);
    return 0;
}
 
template <typename T>
void Sort(T array[], int length) {
    for (int i = 0; i < length-1; i++){
        if (array[i] < array[i+1]) continue;
        array[i] = array[i] + array[i+1];
        array[i+1] = array[i] - array[i+1];
        array[i] = array[i] - array[i+1];
    }
}
 
template <typename T>
void Show(T array[], int length) {
    for (int i = 0; i < length; i++){
        cout << array[i] << '\t';
    }
    cout << endl;
}

运行结果:
1 2 3 4 6
1.1 2.2 3.3 4.4 5.5 6.6
Program ended with exit code: 0

16、函数使用总结:

1、内联函数为了提高运行效率,一般代码较少逻辑简单;
2、参数的引用传递能够节省内在开销,因为C++中参数传递默认为副本拷贝;
3、函数重载能够在函数名相同的情况下根据不同的参数实现不同的功能;
4、函数模板可以一次性实现各种类型参数下的相同业务;
5、默认参数只能在申请或实现时赋值,不能同时赋值;

Leave a Reply