• c++基础(九)


    第三部分:动态存储分配

    用指针访问数组元素

    数组是一组连续存储的同类型数据,可以通过指针的算术运算,使指针依次指向数组的各个元素,进而可以遍历数组。使用指针来访问数组元素时,需要将数组的首地址赋值给指针变量,形式为: int *p,a[10];p=a(或者p=&a[0])。

    经过上述定义及赋值后*pa就是a[0],*(pa+1)就是a[1],... ,*(pa+i)就是a[i]。a[i], *(pa+i), *(a+i), pa[i]都是等效的。

    指针数组

    顾名思义,数组元素是指针的数组就叫做指针数组。我们可以用二维数组来存放矩阵,也可以用一维指针数组来存放矩阵,见下面案例。

    以指针作为函数参数

    为什么需要用指针做参数?

    • 需要数据双向传递时(引用也可以达到此效果)
    • 用指针作为函数的参数,可以使被调函数通过形参指针存取主调函数中实参指针指向的数据,实现数据的双向传递
    • 需要传递一组数据,只传首地址运行效率比较高
    • 实参是数组名时形参可以是指针,数组名作为函数参数时会退化为一个指针

    动态分配与释放内存

    语法格式:new 类型名T  (初始化列表)。其功能为:在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值。结果为:成功:T类型的指针,指向新分配的内存;失败:抛出异常。释放内存:语法格式为 delete 指针p,功能为:释放指针P所指向的内存。

    案例:

    #include <iostream>
    using namespace std;
    class Point 
    {
    public:
        Point() : x(0), y(0)
        {
            cout << "Default Constructor called." << endl;
        }
        Point(int x, int y) : x(x), y(y) 
        {
            cout << "Constructor called." << endl;
        }
        ~Point() { cout << "Destructor called." << endl; }
        int getX() const { return x; }
        int getY() const { return y; }
        void move(int newX, int newY) 
        {
            x = newX;
            y = newY;
        }
    private:
        int x, y;
    };
    
    int main() 
    {
        cout << "Step one: " << endl;
        Point *ptr1 = new Point; //调用默认构造函数
        cout << "ptr1: ";
        cout << ptr1->getX() << "," << ptr1->getY() << endl;
    delete ptr1; //删除对象,自动调用析构函数,释放动态分配的内存空间,不是删除ptr1
        cout << "Step two: " << endl;
        ptr1 = new Point(1, 2);//ptr1存放了新申请的内存空间地址
        cout << "ptr1: ";
        cout << ptr1->getX() << "," << ptr1->getY() << endl;
        delete ptr1;
        //getchar();
        return 0;
    }

    申请和释放动态数组:分配语法:new 类型T  [数组长度];释放语法:delete[] 数组名p。数组长度可以是任何整数类型的表达式,在运行时计算;释放内存时,不要忘记delete后的方括号[],如果没有这对方括号,那么在释放空间时只会释放动态数组的首地址对应的内存空间。

    案例:

    #include <iostream>
    using namespace std;
    class Point 
    {
    public:
        Point() : x(0), y(0)
        {
            cout << "Default Constructor called." << endl;
        }
        Point(int x, int y) : x(x), y(y) 
        {
            cout << "Constructor called." << endl;
        }
        ~Point() { cout << "Destructor called." << endl; }
        int getX() const { return x; }
        int getY() const { return y; }
        void move(int newX, int newY) 
        {
            x = newX;
            y = newY;
        }
    private:
        int x, y;
    };
    
    int main() 
    {
        Point *ptr = new Point[2]; //创建对象数组
        ptr[0].move(5, 10); //通过指针访问数组元素的成员
        ptr[1].move(15, 20); //通过指针访问数组元素的成员
        cout << "ptr[0]: ";
        cout << ptr->getX() << "," << ptr->getY() << endl;
        cout << "ptr[1]: ";
        cout << (ptr + 1)->getX()<<"," << (ptr+1)->getY() << endl;//通过指针访问对象成员名
        cout << "Deleting..." << endl;
        delete[] ptr; //删除整个对象数组
        return 0;
    }

    动态申请多维数组:new 类型名T[第一维长度][第二维长度]…

    案例:

    #include<iostream>
    using namespace std;
    int main()
    {
        int(*cp)[9][8] = new int[7][9][8];
        for (int i = 0; i < 7; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                for (int k = 0; k < 8; k++)
                {
                    //*(*(*(cp + i) + j) + k) = i * 100 + j * 10 + k;
                    cp[i][j][k] = i * 100 + j * 10 + k;
                }
            }
        }
        for (int i = 0; i < 7; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                for (int k = 0; k < 8; k++)
                {
                    cout << cp[i][j][k] << '	';
                }
                cout << endl;
            }
            cout << endl;
        }
        delete[]cp;
        system("pause");
        return 0;
    }

    将动态数组封装成类:更加简洁,便于管理;可以在访问数组元素前检查下标是否越界。

    案例:

    #include <iostream>
    #include<cassert>
    using namespace std;
    class Point
    {
    public:
        Point() : x(0), y(0)
        {
            cout << "Default Constructor called." << endl;
        }
        Point(int x, int y) : x(x), y(y)
        {
            cout << "Constructor called." << endl;
        }
        ~Point() { cout << "Destructor called." << endl; }
        int getX() const { return x; }
        int getY() const { return y; }
        void move(int newX, int newY)
        {
            x = newX;
            y = newY;
        }
    private:
        int x, y;
    };
    class ArrayofPoints//定义一个动态数组类
    {
    public:
        ArrayofPoints(int size) :size(size)//初始化
        {
            points = new  Point[size];//动态分配存储空间
        }
        ~ArrayofPoints()//析构函数
        {
            cout << "Deleting..." << endl;
            delete[]points;//释放存储空间
        }
        Point& element(int index)//返回数组中类对象的引用,这样可以对对象进行操作
        {
            assert(index >= 0 && index < size);//检查数组下标是否越界
            return points[index];
        }
    private:
        Point *points;
        int size;
    };
    int main()
    {
        int count;
        cout << "Please enter the count of points:";
        cin >> count;
        ArrayofPoints points(count);
        for (int i = 0; i < count; i++)
        {
            points.element(i).move(i, i+5);
        }
        for (int i = 0; i < count; i++)
        {
            cout << "points[" << i << "]:" << "(" << points.element(i).getX() << ",";
            cout<< points.element(i).getY()<<")" << endl;
        }
        return 0;
    }

    运行结果:

    智能指针:

    • 显式管理内存在性能上有优势,但容易出错。
    • C++11提供智能指针的数据类型,对垃圾回收技术提供了一些支持,实现一定程度的内存管理
    • unique_ptr :不允许多个指针共享资源,可以用标准库中的move函数转移指针
    • shared_ptr :多个指针共享资源
    • weak_ptr :可复制shared_ptr,但其构造或者释放对资源不产生影响
  • 相关阅读:
    mysql表结构转hive表结构,字段映射脚本
    kafka 相关命令 偏移重置
    Specified key was too long; max key length is 767 bytes
    java IO 流关系图谱
    jvm 性能监控与linux常用命令
    jupiter的@TempDir 等不生效
    mysql 深度分页
    jedis的ShardedJedisPool链接池的扩容问题
    拜读《三国》看懂男人
    linux 性能优化
  • 原文地址:https://www.cnblogs.com/puheng/p/9345943.html
Copyright © 2020-2023  润新知