C++实训

C++实训

Jexi Jiang Lv3

每个 IDE的工程文件不一样

好习惯

  1. 判空再释放

    1
    2
    3
    4
    5
    if( NULL != rest ){
    free(rest);
    rest = NULL;//可以避免重复置空(free)带来的报错
    }

day_01

数据类型

part1

sizeof()是操作符,不是函数

  • b[40]数据类型到底是什么???

    1
    2
    3
    4
    5
    6
    7
    int b[10];//10*4 = 40 字节  数据类型是什么?
    /*
    * b数组名:代表数组首元素的地址
    * b+1: 加一个数组元素
    * &b: 对数组名取地址,代表的是整个数组的地址。这个数组的数据类型是?有10个int元素的数组。
    * &b+1:加一个数组
    */
  • 数据类型的本质

    • 固定内存大小的别名
  • 变量的本质

    • 一段连续内存空间的别名

part2

  • void*是无类型指针

    • 可以接收任何数值

    • 在数据的封装方面用处很大

      • void*作为左值(放在赋值符号的左边),能“接收”任意类型的支持指针

      • void* 作为右值

        • int* p = NULL;
          char* p2 = (char*)malloc(sizeof(char) * 20);//malloc返回void*,所以要(char*)强制类型转换
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
            * 不存在 `void`类型的变量

          ### part3

          * 数据类型取别名

          * `typedef 原来的名字 你要改的名字`

          * `eg.`: `typedef unsigned int u32`
          * `eg.`定于10个int元素的数据类型

          * `int [10]`—>`typedef int xxx [10]`(xxx是你定义的名字)
          * ```c++
          //在c++中直接给数组取别名
          int(&你起的名字)[3] = b;

part4

  • 内存

image-20240116111708201

  • 程序生成的二级制文件分为两个部分——每次数据不同,但代码相同,所以分开

    • 代码区

    • 数据区

      • 全局区与静态区

        • 全局区
          • extern int a = 5
          • extern可以不写
        • 静态区
          • `static int a = 5
        • 常量区
          • 尽量不要修改字符串常量
          • string是可读不可写
    • 比如查看2.2这个文件

      1
      2
      * text表示代码段的大小
      * 数据区大小 = data(已经初始化数据)+bss(未初始化数据)
  • 分区模型

    image-20240115161010377

重要模型

  • void allocSpace(char **p)
    {
        char *temp = (char*)malloc(sizeof(char)*100);
        if(NULL == temp){
            return;
        }
        memset(tem, 0, 100);
        strcpy(temp, "hello world!");
        *p = temp;
    }
    int main
    {
        char *p = NULL;
        allocSpace(&p);
        printf("p = %s\n", p);
        if(NULL != p){
            free(p);
            p = NULL;
        }
    }
    
    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

    ### part5

    * 栈的生长方向

    * 有向上和向下两种
    * 画图,内存是由低地址到高地址分配。
    * 大端模式与小端模式

    * 大端模式:高字节存储在低地址
    * 小端模式:低字节存储在低地址(高位字节指向低位字节)

    # day_02

    ## 指针和指针变量

    * 指针是一种数据类型
    * 具有固定大小的数据类型
    * 指针变量是一种变量
    * 一段连续内存的别名
    * 不允许向 `NULL`或非法地址拷贝内存

    ### 野指针

    * 什么情况下会导致野指针
    * 指针变量没有初始化
    * 指针指向的内存释放了,但指针没有置空
    * 越界访问
    * `char str[3] = "abc";`越界了,3要变成4.

    ### 指针的特性

    1. 指针的步长

    * 指针的步长取决于指针所指向的数据类型。
    * 不同的数据类型在内存中占用不同数量的字节,因此指针在移动时会按照相应的步长进行跳跃。

    ```c++
    char* p = NULL;
    printf("%d\n", p);//0
    printf("%d\n", p+1);//1

    int* q = NULL;
    printf("%d\n", q);//0
    printf("%d\n", q + 1);//4

    char buf[1024] = { 0 };
    printf("%d\n", buf);//-19334423
    printf("%d\n", buf+1);//-19334422
    printf("%d\n", &buf);//-19334423
    printf("%d\n", &buf+1);//-19334423+1024
    * 小巧思 * ```c++ char buf[1024] = { 0 }; //存入int100000 int a = 100000; memcpy(buf + 1, &a, sizeof(int));//三个参数:目的地,源地址,拷的字节大小 //从buf把100000输出 char* p2 = buf; printf("%d\n", *((int*)(p2 + 1)));//指向目的地,类型转换为int*(即4个字节),解引用。天才!!!
    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
    66
    67
    68
    69
    70
    71
    72
    2. 指针输入输出特性

    * 数组为函数传入参数时:会退化为指针

    * 所以在函数内部是算不出来数组的长度的
    * 要在外部算好后传入进来
    * 示例

    * ```c++
    /*
    * char *p = "abcd12312ab34523abcda98367abced37abcd2qq"
    * 求字符串中“abcd”出现的次数:
    * 1、请自定义函数接口,完成上面需求。(50分)
    * 2、自定义业务函数和main函数,设计测试用例进行测试(50分)
    */
    //返回值 函数名 (参数列表)
    /*
    * 功能:求子串在母串中出现的次数
    * author:zw
    * time:
    * 返回值:0:表示成功执行正常退出,-1:输入参数为空,1:
    * 参数:char* str:指向母串的指针,输入参数。
    char* substr:指向子串的指针,输入参数.
    int* count:求子串在母串中出现的次数,输出参数
    */

    int getSubCount(char* str/*in*/, char* substr/*in*/, int* count/*out*/);//一般在.h的头文件中
    int getSubCount(char* str/*in*/, char* substr/*in*/, int* count/*out*/)//一般放在源文件,.c .cpp
    {
    //参数有效性验证
    if (NULL == str || NULL == substr || NULL == count)
    {
    return -1;
    }
    //子串匹配
    char* p = str;
    char* sub = substr;
    int m_count = 0;

    while (*p != '\0')
    {
    p = strstr(p, sub);
    if (p != NULL)
    {
    m_count++;
    p = p + strlen(sub);

    }
    else
    {
    break;
    }
    }

    *count = m_count;
    return 0;
    }

    int main()
    {
    char* str = "abcd12312ab34523abcda98367abced37abcd2qq";
    char* substr = "abcd";
    int count = 0;
    int result = getSubCount(str, substr, &count);
    if (result != 0)
    {
    printf("error:func getSubCount error code %d", result);
    return;
    }
    printf("count: %d\n", count);
    return 0;
    }

数组指针和指针数组

  • 数组指针

    • 是一个指针

      • 定义方法一:int(*ppArr)[3] = &arr;

      • 定义方法二:

        1
        2
        3
        int arr[3] = { 1,2,3 };
        typedef int ARR_TYPE[3];
        ARR_TYPE* pArr = &arr;
  • 指针数组

    • 是一个数组(元素为指针的数组)

      1. 栈区指针数组

        • char* ptr[] 表示字符指针数组。
        • char** ptr 在函数参数中,数组退化为指针,所以二者等效
      2. 堆区指针数组

        • 数组本身要有空间,指向的指针也要有空间

          • char* *p = (char **)malloc(sizeof(char*) * len);
          • ptr[i] = (char*)malloc(sizeof(char) * 100);
          • //释放资源
                for (int i = 0; i < len; i++)
                {
                    if (ptr[i] != NULL)
                    {
                        free(ptr[i]);
                        ptr[i] = NULL;
                    }
                }
            
                if (ptr != NULL)
                {
                    free(ptr);
                    ptr = NULL;
                }
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            3. 设计出具有自我结束能力的指针数组

            ```c++
            void test11(){
            char* ptr1[] = { "aaa","bbb","ccc",0 };
            char* ptr2[] = { "aaa","bbb","ccc",NULL };
            char* ptr3[] = { "aaa","bbb","ccc","\0"};
            for (int i = 0; ptr1[i] != NULL; i++)
            {
            printf("%s\n", ptr1[i]);
            }
            }

函数指针和指针函数

函数是一种数据类型。将函数这种数据类型定义出来,然后定义指针。

  1. 函数指针

    🌸 函数指针应用场景:做函数参数——回调函数

    一个函数在编译的时候,会分配一个入口地址。这个地址就是函数的指针。函数名代表函数的入口地址。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int add(int a, int b)
    {
    return a + b;
    }
    //1.先定义函数类型,然后通过类型定义指针
    typedef int (FUNC_TYPE) (int, int)
    FUNC_TYPE* myadd = add;
    int result = myadd(10, 30);
    //2.直接定义函数指针类型
    typedef int(* FUNC_pTYPE)(int, int);
    FUNC_pTYPE f = add;
    int result = f(10, 30);
    //3.直接定义函数指针变量
    int(*func)(int, int) = add;
    int result = func(10, 50);//func是指针,代表函数的入口地址。
    result = (*func)(100, 200);//*func是函数名字,函数名代表函数的入口地址。

    • 函数指针数组

      是个数组,其中每个元素是函数指针。

重要模型

🔴eg: 统一接口

  • void printAllArray(void* arr *in*/, int len /*in*/, int elemSize /*in*/, print_type print)
    • void*表示任意参数可传入
    • print_type print
      • 之前定义了 typedef void(*print_type)(void*);函数指针当参数回调
      • 对于不同数据类型的打印参数额外定义,如 void printInt(void* data)

Day_03

单链表

  • image-20240117160328862把节点放到结构体内,更加符合统一性和拓展性需求。

  • 异常处理

    • throw

      • catch

        1
        2
        3
        4
        5
        try{
        }
        catch{

        }

智能指针

第三方库有很多

模板

泛型编程 数据类型参数化

  • template <typename T>
    void myswap(T &a, T &b)
    {
        T t;
        t = a;
        a = b;
        b = t;
    }
    //这样用
    //myswap<int>(a, b);
    
    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
    * 标准模板库 `STL`: 容器  算法 仿函数(函数对象,谓词),迭代器,适配器

    * `vector`
    * `iterator`
    * `map`
    * 函数对象: 类重载函数调用(),这个类的对象称为函数对象(仿函数)

    * ```c++
    template<typename T>
    class ShowElement
    {
    public:
    ShowElement()
    {
    mCount = 0;
    }
    void operator()(T elem)
    {
    mCount++;
    cout << elem << " ";
    }
    void printCount()
    {
    cout << mCount << endl;
    }
    private:
    int mCount;
    };

    void test04()
    {
    int a = 100;
    ShowElement<int> showElement;
    showElement(a); //showElement.operator()(100)
    cout << endl;
    }

Day_04

Qt

  • Title: C++实训
  • Author: Jexi Jiang
  • Created at : 2024-01-15 13:43:26
  • Updated at : 2024-01-18 22:03:12
  • Link: https://milefer7.github.io/Jaxi-Jiang-Blog/2024/01/15/C++实训/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments