• C++基础从0到1入门编程(二)


    系统学习C++
    方便自己日后复习,错误的地方希望积极指正
    往期文章:C++基础从0到1入门编程(一)
    参考视频:
    1.黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
    2.系统化学习C++

    1 函数指针和回调函数

    如果把函数的地址作为参数传递给函数,就可以在函数中灵活的调用其他函数
    三步走:
    (1)声名函数指针

    int fun(int a, string b);
    //函数指针的声明
    int (*pfun)(int, string);
    
    • 1
    • 2
    • 3

    (2)让函数指针指向函数的地址

    pfun = fun;
    
    • 1

    (3)通过函数指针调用函数

    (*pfun)(2,"asd"); // C
    pfun(2,"asd");    // C++
    
    • 1
    • 2
    #include 
    #include 
    using namespace std;
    
    void func(int no, string str)
    {
        cout << no << ' ' << str;
    }
    int main()
    {
        int bh = 3;
        string message = "i'm a dog";
        func(bh, message);
        // 声明函数指针
        void (*pfunc)(int, string);
        // 对函数指针赋值,函数指针名 = 函数名
        pfunc = func;
        // 用函数指针名调用函数 C++
        pfunc(bh, message);
        // 用函数指针名调用函数 C语言
        (*pfunc)(bh, message);
        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

    函数指针的使用场景(回调函数):

    开了一个皮包公司,专门承接表白业务
    表白之前的准备工作和表白之后的收尾工作,公司都帮你做好,向女生表白这件事由你自己来做,别人是帮不了的。

    用函数指针回调函数和用函数名调用函数意义不一样
    回调函数:把一个函数的代码嵌入到另一个函数中,调用者函数提供了主体的流程和框架,具体的功能由回调函数来实现。写调用者函数的时候,只确定回调函数的种类,不关心回调函数的功能。

    函数名调用函数:调用函数时,知道函数名和功能

    #include 
    using namespace std;
    
    void BigDavid(int a)
    {
        cout << a << "Hello World" << endl;
    }
    
    void Hw(int a)
    {
        cout << a << "asd\n";
    }
    //void show(void (*pf)())
    //{
    //    cout << "front" << endl;
    //    pf();
    //    cout << "done" << endl;
    //}
    
    void show(void (*pf)(int), int b)
    {
        cout << "front" << endl;
        pf(b);
        cout << "done" << endl;
    }
    
    int main()
    {
        show(BigDavid, 3);
        show(Hw, 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

    2 补充一些数组的概念

    2.1 清空数组和复制数组

    (1)清空数组
    memset()函数可以把数组中全部元素清零(适用于C++基本数据类型)
    void *memset(void *s, int c, size_t n);
    在Linux下,使用memcpy()函数要加头文件#include
    (2)复制数组
    用memcpy()函数可以将数组中全部的元素复制到另一个相同大小的数组
    void *memcpy(void *dest, const void *src, size_t n);
    第一个参数:目标数组名
    第二个参数:原数组名
    第三个参数:整个数组占用内存空间的大小

    #include 
    #include 
    using namespace std;
    
    int main()
    {
        int bh[] = {1, 2, 4, 6};
        string name[3];
    
        for (int i = 0; i < 4; i++)
        {
            cout << i << ' ' << bh[i] << endl;
        }
        memset(bh,0,sizeof(bh));
        for (int i = 0; i < 4; i++)
        {
            cout << i << ' ' << bh[i] << endl;
        }
    
        int bh1[sizeof(bh) / sizeof(int)];
        memcpy(bh1, bh, sizeof(bh));
        for (int i = 0; i < 4; i++)
        {
            cout << i << ' ' << bh1[i] << endl;
        }
    
    }
    
    • 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
    2.2 一维数组用于函数的参数

    1.指针的数组表示
    数组名[下标] = *(数组首地址 + 下标)
    地址[下标] = *(地址 + 下标)

    #include 
    using namespace std;
    
    int main()
    {
        char a[20];
        int* p = (int *)a;
        for (int i = 0; i < 5; i++)
        {
            p[i] = i + 300;
        }
        for (int i = 0; i < 5; i++)
        {
            cout << *(p + i) << endl;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.一维数组用于函数的参数
    void fun(int* arr, int len);
    void fun(int arr[], int len);

    #include 
    using namespace std;
    
    void func(int arr[], int len)
    {
        for (int i = 0; i < len; i++)
        {
            cout << arr[i] << endl;
        }
    }
    int main()
    {
        int a[] = {1, 2, 4, 5};
        func(a, 4);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    2.3 用new动态创建一维数组

    数据类型 *指针 = new 数据类型[数组长度];
    释放一维数组的语法:delete[] 指针;

    #include 
    using namespace std;
    
    int main()
    {
        int* arr = new int[8];
        for (int i = 0; i < 8; i++)
        {
            arr[i] = 100 + i;
            cout << *(arr + i) << endl;
        }
        delete[] arr;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Tip:
    (1)动态创建的数组没有数组名,不能用sizeof运算符
    (2)可以用数组表示法和指针表示法使用动态创建的数组
    (3)必须使用delete[]释放内存
    (4)不要用delete[]释放不是new[]分配的内存
    (5)不用delete[]释放同一个内存块两次(否则相同于操作野指针)
    (6)对空指针用delete[]是安全的(释放内存后,应该把指针置空nullptr)
    (7)声名普通数组,数组长度可以用变量,相当于在栈上动态创建数组,并且不需要手动释放
    (8)非常重要:如果内存不足,调用new会产生异常,导致程序终止;如果在new关键字后面加(std::nothrow)选项,则返回nullptr,不会产生异常

    #include 
    using namespace std;
    
    int main()
    {
        int *a = new (std::nothrow) int[10000000001];
        if (a == nullptr)
        {
            cout << "failed" << endl;
        }
        else
        {
            a[10000000000] = 8;
            delete[] a;
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    (9)为什么用delete[]释放数组的时候,不需要指定数组的大小?因为系统会自动跟踪已分配数组的内存

    2.4 数组最经典的两种应用场景:排序和查找

    (1)数组的排序qsort
    qsort()函数用于对各种数据类型的数组进行排序
    void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void *))
    第一个参数:数组的起始地址
    第二个参数:数组元素的个数
    第三个参数:数组元素的大小(sizeof(数组的数据类型))
    第四个参数:回调函数的地址

    回调函数决定了排序的顺序
    int compar(const void* p1, const void* p2);
    1)如果函数的返回值< 0 ,那么p1所指向元素会被排在p2所指向元素的前面。
    2)如果函数的返回值==0,那么p1所指向元素与p2所指向元素的顺序不确定。
    3)如果函数的返回值> 0 ,那么p1所指向元素会被排在p2所指向元素的后面。

    qsort()函数细节
    (1)形参中的地址用void是为了支持任意数据类型,在回调函数中必须具体化
    (2)排序的需求除了升序和降序,还有很多不可预知的情况,只能用回调函数

    #include 
    using namespace std;
    // 从小到大排序
    int compasc(const void* p1, const void* p2) // 升序的回调函数
    {
    //    if (*(int*)p1 < *(int*)p2) return -1;
    //    if (*(int*)p1 == *(int*)p2) return 0;
    //    if (*(int*)p1 > *(int*)p2) return 1;
        return *(int*)p1 - *(int*)p2;
    }
    int compdesc(const void* p1, const void* p2) // 降序的回调函数
    {
        return *(int*)p2 - *(int*)p1;
    }
    int main()
    {
        int a[8] = { 2,1,7,8,4,0, 11, 9};
        for (int i = 0; i < 8; i++)
        {
            cout << a[i] << ' ';
        }
        cout << endl;
        qsort(a,sizeof(a)/sizeof(a[0]),sizeof(a[0]),compdesc);
        for (int i = 0; i < 8; i++)
        {
            cout << a[i] << ' ';
        }
        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

    (2)数组的查找
    二分法详见:数组之二分查找

    2.5 C风格字符串

    C++用的是string,能自动扩展,不考虑内存和野指针问题

    string是C++的类,封装了C风格的字符串
    在某些场景,C风格字符串更方便、高效

    C语言约定:如果字符型(char)数组的末尾包含了空字符\0(也就是0),那么该数组中的内容就是一个字符串

    #include 
    using namespace std;
    int main()
    {
        string x = "XY";
        cout << x[0] << x[1] << x[2];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    一些操作
    (1)初始化

    char name[11];
    char name[11] = { "hello" };
    char name[] = { "sd" };
    char name[11] { "hello" };
    char name[11] = { 0 }; //把全部元素初始化为0
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (2)清空字符串

    memset(name, 0, sizeof(name));
    name[0] = 0; //不推荐
    
    • 1
    • 2

    (3)字符串复制strcpy()
    复制完字符串后,会在dest后追加0
    如果参数dest所指的内存空间不够大,会导致数组的越界

    strcpy(name1, name);
    
    • 1

    将参数name字符串拷贝至参数name1所指的地址
    (4)字符串赋值strncpy

    strncpy(name1, name, 3);
    
    • 1

    把name前3个字符的内容复制到name1中

    如果src字符串长度小于n,则拷贝完字符串后,在dest后追加0,直到n个。
    如果src的长度大于等于n,就截取src的前n个字符,不会在dest后追加0。
    如果参数dest所指的内存空间不够大,会导致数组的越界。

    (5)获取字符串的长度strlen()
    (6)字符串拼接strcat()
    (7)字符串拼接strncat()
    (8)字符串比较strcmp()和strncmp()
    相等返回0,str1大于str2返回1,str1小于str2返回-1

    strcmp(str1, str2);
    strcmp(str1, str2, 3);
    
    • 1
    • 2

    (9)查找strchr()和strchr()
    const char *strchr(const char *s, int c);
    返回在字符串s中第一次出现c的位置,如果找不到,返回0。
    const char *strrchr(const char *s, int c);
    返回在字符串s中最后一次出现c的位置,如果找不到,返回0。
    (10)查找字符串strstr()
    char * strstr(const char* str,const char* substr);
    功能:检索子串在字符串中首次出现的位置。
    返回值:返回字符串str中第一次出现子串substr的地址;如果没有检索到子串,则返回0。

    #define _CRT_SECURE_NO_WARNINGS
    #include 
    #include 
    using namespace std;
    int main()
    {
        // 初始化方法
        char name[11]; // 存放了10个字符,没有初始化,里面都是垃圾值
        char name1[11] = "hello";
        char name2[] = { "asd" }; //4
        char name3[11] = { "asd" };
        char name4[11] {"asd"}; // C++11标准
        char name5[11] = {0};
    
        for (int i = 0; i < 11; i++)
        {
            cout << name1[i] << endl;
        }
        // 清空字符串
        memset(name1, 0, sizeof(name));
    
        // 字符串复制或赋值strcpy()
        strcpy(name, name3);
    
        // 字符串赋值或赋值strncpy()
        strncpy(name, "hello", 8);
    
        // 获取字符串的长度strlen()
        cout << strlen(name) << endl;
    
        // 字符串拼接strcat()
        cout << strcat(name, name3) << endl;
    
        // 字符串拼接strncat()
        cout << strncat(name, name3, 2) << endl;
    
        // 字符串比较strcmp()和strncmp()
        cout << strcmp(name1, name2) << endl;
        cout << strncmp(name1, name2, 2) << endl;
    
        // 字符查找strchr()和strtchr()
        cout << strchr(name1, 0) << endl;
        // 字符串查找strstr()
        cout << strstr(name1, name2) << endl;
    }
    
    • 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

    (11)Tip
    1.结尾标志0后面都是垃圾内容
    2.字符串每次使用前都要初始化
    3.不要在子函数中对字符指针用sizeof运算,所以,不能在子函数中对传入的字符串进行初始化,除非字符串的长度也作为参数传入到了子函数中。

    2.6 二维数组一些补充

    其他一些基本概念在C++基础从0到1入门编程(一)
    (1)清空二维数组
    用memset()函数把二维数组中全部的元素清零
    (2)复制二维数组memcpy()
    (3)二维数组用于函数的参数
    复习之前学过的指针

    int* p;            // 整型指针
    int* p[3];         // 一维整型指针数组
    int* p();          // 函数p的返回值类型是整型的地址
    int (*p)(int, int);// p是函数指针,函数的返回值是整型
    
    • 1
    • 2
    • 3
    • 4

    行指针
    数据类型 (*行指针名)[行的大小];

    int (*p1)[3];  // p1是行指针,用于指向数组长度为3的int型数组
    
    • 1

    二维数组名是行地址

    int bh[2][3] = { {1, 2, 3}, {2, 1, 4} };
    
    • 1

    bh是二维数组名,该数组有两元素,每一个元素本身又是一个数组长度为3的整型数组。

    bh:数组长度为3的整型数组类型的行地址
    如果存放bh的值,要用数组长度为3的整型数组类型的行指针

    int bh[2][3] = { {1, 2, 3}, {2, 1, 4} };
    int (*p)[3] = bh;
    
    int bh[4][2][3];
    int (*p)[2][3] = bh;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    把二维数组传递给函数
    void fun(int (*p)[3], int len);
    void fun(int p[][3], int len);
    实操:

    #include 
    #include 
    using namespace std;
    
    //void fun(int p[][3], int len)
    //{
    //    for (int i = 0; i < len; i++)
    //    {
    //        for (int j = 0; j < 3; j++)
    //        {
    //            cout << p[i][j] << " ";
    //        }
    //        cout << endl;
    //    }
    //}
    void fun(int (*p)[2][3])
    {
        int i = 0;
        for (int a = 0; a < 4; a++)
        {
            for (int b = 0; b < 2; b++)
            {
                for (int c = 0; c < 3; c++)
                {
                    p[a][b][c] = i++;
                }
            }
        }
    }
    int main()
    {
        int a[10];
        cout << a + 1<< endl;  // +4
        cout << &a + 1<< endl; // +40
    
        // int bh[2][3] = { {1, 2, 3}, {2, 1, 4} };
        // fun(bh, 2);
        int bh[4][2][3];
        memset(bh, 0, sizeof(bh));
        fun(bh);
        for (int a = 0; a < 4; a++)
        {
            for (int b = 0; b < 2; b++)
            {
                for (int c = 0; c < 3; c++)
                    cout << bh[a][b][c] << '\t';
                cout << endl;
            }
            cout << endl << endl;
        }
    }
    
    • 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

    3 结构体基本概念

    3.1 定义结构体

    结构体:将多种数据整合到一起,描述一个完整的对象
    Tip:
    (1)结构体成员可以用C++的类(string),但是不提倡
    (2)C++中,结构体可以有函数,不推荐
    (3)C++中,定义结构体可以指定缺省值

    3.2 创建结构体变量

    struct 结构体名 结构体变量名;
    struct 结构体名 结构体变量名={成员一的值, 成员二的值,…, 成员n的值}
    如果大括号内未包含任何东西或只写一个0,全部的成员都将被设置为0
    Tip: C++中,struct关键字可以不写;可以在定义结构体的时候创建结构体变量

    3.3 使用结构体

    结构体变量名.结构体成员名;

    3.4 占用内存的大小

    使用sizeof运算符可以得到整个结构体占用内存的大小

    整个结构体占用内存的大小不一定等于全部成员占用内存之和

    3.5 清空结构体

    用memset()函数可以把结构体中全部的成员清零。
    bzero()函数也可以。

    3.6 复制结构体

    使用memcpy()函数把结构体中的全部元素复制到另一个相同类型的结构体,也可以直接用=

    实操:

    #include 
    #include 
    using namespace std;
    #pragma pack(8)
    
    struct girl
    {
        char name[20];
        int age;
        double weight;
        char sex;
        bool yanzhi;
    };
    
    int main()
    {
        girl girl{"DiaoChan", 26, 99.9, 'X', true};
        cout << sizeof(girl) << endl;
        memset(&girl, 0, sizeof(girl));
        cout << girl.name << ' ' << girl.age << ' ' << girl.weight << ' ' << girl.sex << ' ' << girl.yanzhi << 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

    4 结构体指针

    C++中,用不同类型的指针存放不同类型变量的地址,这一规则也适用于结构体

    4.1 语法
    struct Girl girl;
    struct Girl *pst = &girl; // 声明结构体指针,指向结构体变量
    
    • 1
    • 2

    通过结构体指针访问结构体成员

    (*指针名).成员变量名
    指针名->成员变量名 // 通常用这个,直观
    
    • 1
    • 2
    4.2 用于函数的参数

    如果把结构体传递给函数,实参取结构体变量的地址,函数的形参用结构体指针
    如果不希望在函数中修改结构体变量的值,可以对形参加const约束

    4.3 用结构体指针指向动态分配的内存的地址

    结构体指针指向动态分配的内存的地址

    #define _CRT_SECURE_NO_WARNINGS // 如果要使用C标准库的字符串函数,需要加上这一行代码
    #include 
    #include 
    using namespace std;
    
    struct Girl
    {
        char name[20];
        int age;
        double weight;
        char sex;
        bool yanzhi;
    };
    
    void fun(const Girl* pst)
    {
        cout << pst->name << ' ' << pst->age << ' ' << pst->sex << ' ' << pst->weight << ' ' << pst->yanzhi;
    }
    int main()
    {
        Girl* girl = new Girl({"DiaoChan", 26, 99.9, 'X', true});
        fun(girl);
        delete girl;
        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

    5 结构体数组

    struct 结构体类型 数组名[数组长度];

    #define _CRT_SECURE_NO_WARNINGS // 如果要使用C标准库的字符串函数,需要加上这一行代码
    #include 
    #include 
    using namespace std;
    
    struct Girl
    {
        char name[20];
        int age;
        double weight;
        char sex;
        bool yanzhi;
    };
    
    int main()
    {
        Girl girls[3];
        memset(girls, 0, sizeof(girls));
        girls[1] = {"xigua",2,10.2,'X',false};
        strcpy(girls[0].name, "asd");girls[0].age = 11; (girls + 0)->yanzhi = true;
        for (int i = 0; i < 3; i++)
        {
            cout << (girls + i)->name << ' ' << girls[i].age << 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

    6 结构体嵌入数组和结构体

    多维数组用于函数的参数
    做法:把二维或者多维数组放在结构体中,作为结构体的一个成员,调用函数的时候,把结构体的地址传给函数,函数的形参接受结构体的地址,这样就可以绕过二维和多维数据传指针的问题。

    #include 
    using namespace std;
    
    struct st_girl
    {
        char name[21];
        int score[2][3] = {1,3,4,2,2,1};
        int age;
        double weight;
        char sex;
        bool yz;
    };
    
    void fun(st_girl* pst)
    {
        for (int a = 0; a < 2; a++)
        {
            for (int b = 0; b < 3; b++)
            {
                cout << pst->score[a][b] << ' ';
            }
            cout << endl;
        }
    }
    int main()
    {
        st_girl girl;
        fun(&girl);
    }
    
    • 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;
    
    struct st_pet
    {
        char name[21];
        char type[21];
    };
    
    struct st_girl
    {
        char name[21];
        int age;
        double weight;
        char sex;
        bool yz;
        struct st_pet pet;
    };
    
    int main()
    {
        st_girl girl = {"bigDavid",23,50.5,'X',true,{"as","ass"}};
        cout << girl.name << ' ' << girl.pet.type << ' ' << girl.pet.name << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    7 结构体中的指针

    如果结构体的指针指向的是动态分配的内存地址
    (1)对结构体用sizeof没有意义
    (2)对结构体用memset()函数可能会造成内存泄露(申请了堆区指针不释放)
    在没有动态分配内存之前,是可以用memset()函数清空结构体
    在没动态分配内存之后,逐个清空

    #include 
    #include 
    using namespace std;
    
    struct st_t
    {
        int a;
        int* p;
    };
    
    int main()
    {
        st_t stt;
        // memset(&stt, 0, sizeof(st_t));
    
        stt.a = 3;
        stt.p = new int[100];
    
        cout << sizeof(stt) << endl; // 16
        cout << stt.a << ' ' << stt.p << endl;
        // 清空成员a
        stt.a = 0;
        // 清空成员p指向的内存中的内容
        memset(stt.p, 0, 100*sizeof(int));
        cout << stt.a << ' ' << stt.p << endl;
        delete[] stt.p; 
    }
    
    • 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

    (3)C++中的string中有一个指向的是动态分配的内存地址指针

    struct string
    {
    	char *ptr;	
    };
    
    • 1
    • 2
    • 3
    • 4

    memset一个带有指针成员类型是未定义的行为,不同编译器处理不一样,行为未定义结果肯定也未定义。string是c++封装的一个带有指针成员的类

    string类的构造函数在构造string对象时,str_data指针会指向堆中字符串长度加1大小的内存空间,而使用memset函数对string类型对象清零后str_data变成了0,指向原内存空间在析构函数中不会被释放,导致内存泄漏。
    不要轻易0初始化string、vector等STL标准容器及具有动态内存管理的类

    #include 
    #include 
    using namespace std;
    struct st_girl
    {
        string name;
    };
    int main()
    {
        st_girl girl;
        girl.name = "BigDavid";
        cout << girl.name << endl;
        //memset(&girl, 0, sizeof(girl));
        girl.name = "Liu";
        cout << girl.name << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    人工智能之地形导航系统
    docker管理之consul注册中心
    java算法题Day33
    2023 INCLUSION·外滩大会丨拓数派科技战略深度披露,大模型数据计算系统蓄势待发
    MindFusion.Diagramming for Java 4.6.2
    资深技术官聊聊Java程序员三年这个“梗”,该如何突破自身瓶颈?
    [LeetCode][54]【学习日记】螺旋遍历二维数组
    Java基础复习 Day 20
    【视觉高级篇】19 # 如何用着色器实现像素动画?
    springboot 数据翻译:支持枚举翻译、字典翻译、外键翻译、级联翻译、方法翻译
  • 原文地址:https://blog.csdn.net/BigDavid123/article/details/134454940