「数组」实现动态数组的功能 / 数据结构模版(C++)

C/C++动态内存分配之用malloc和指针实现动态数组排序 /************************************************************************/ /*动态数组解决了静态数组对内存空间的耗用问题,同时由于其使用的是指针,所以 在多函数调用上快速、便捷。 用malloc和指针定义动态数组,其关键是要准确理解指针的含义和数组的操作手段。 此程序的功能是用动态内存分配的手段实现输入数组的排序。 阅读详情

目录

概述

命名空间

成员变量

创建销毁

整体赋值

内存管理 

数据控制

数据访问

Code


概述

动态数组,顾名思议即可变长度的数组。数组这种数据结构的实现是在栈空间或堆空间申请一段连续的可操作区域。

实现可变长度的动态数组结构,应该有以下操作:申请一段足够长的空间,如果数据的存入导致空间已满,则申请一段更长的空间,将原有数据复制过去后加入新数据,同时释放原空间。

//栈空间(在栈上原地生成长度为len的数组空间)
int arr[len];

//堆空间(在堆上申请长度为len的空间,获得首地址交给指针arr)
int *arr=new int[len];

//在堆上实现动态数组
int *temp=new int[len*2];//申请更长的空间
strcpy(temp,arr,sizeof(int)*len)//strcpy以字节为单位将arr指向的数据复制到temp中
delete[]arr;//释放原空间
arr=temp;//temp赋值给arr

接下来我们通过封装array类,实现动态数组的一些基本功能 。(Code和测试案例附后)


命名空间

C++有自己的std命名空间下的array,为了进行区分,封装一个自己的动态数组命名空间custom_dynamic_array。

使用namespace关键字封装,使用时可以声明using namespace custom_dynamic_array;全局声明,或custom_dynamic_array::局部声明。

namespace custom_dynamic_array{
    ...
}

//全局声明
using namespace custom_dynamic_array;

//局部声明
custom_dynamic_array::...
 

成员变量

定义class类array,封装三个成员变量:T*val; size_t val_size; size_t val_capacity;

(size_t 是C/C++标准在stddef.h中定义的(这个头文件通常不需要#include),size_t 类型专门用于表示长度,它是无符号整数。)

template <typename T>是泛型,作为数组这种数据结构,他的数据单位应该是任意一种类型(int,double,class等),template <typename T>的作用区域是它随后的一个{}内,意为T将代表某种类型,至于某种类型到底是那种类型,将在class实例化时告知(如arrar<double> arr,这句话的意思是创建一个储存double类型的动态数组类)

T* val表示指向array维护的存放数据的空间的指针val。

size_t size表示数组的当前存入内容的长度(数据长度)。

size_t val_capacity是数组的空间大小(真实长度)。

为什么维护了size和capacity两种长度?试想:每次申请长度都只是当前长度+1,则会在内存空间中反复向后利用函数申请新空间来维护数据,这同时耗费了时间和空间。

那么如果每次都申请真实长度size的两倍空间capacity,则每次申请后都有一段空闲区域容纳新元素,此时不需要申请新空间,只有当再次填满时才申请新空间,则减少了时间成本,提高了空间利用率。

namespace custom_dynamic_array{
    template <typename T>
    class array {
    private:
	    T* val;
	    int val_size;
	    int val_capacity;
    public:
        ...
    }
}

创建销毁

我们提供七种构造函数(创建动态数组)和一个析构函数(销毁动态数组)。

无参构造:arary(),初始化val_size=0,val_capaciy=1(如果等于0的话,后续申请两倍capacity会失效),val=nullptr(空指针)。

(初始化列表array():成员变量(x),...{}在构造函数后加上:即为初始化列表,表示为成员变量赋为括号内的值x,而无须写入{}中)

提供初始空间的构造:array(const int num),表示申请初始空间为num的动态数组。

(断言assert(num>0),定义在assert.h头文件中,在运行时会判断括号内的条件为真,否则抛错,用于保护程序运行的安全)

提供初始长度和初值的构造:array(const int size,T target_val),为val指针申请两倍size的空间,利用for循环填充长度为size的初始值。

提供源数据地址的构造:array(const T* begin,const T* end),从定长度数组中获取数据进行初始化,定义int size=end-begin(指针减法获得两指针的间隔长度(以指向的数据类型为单位))

(内存拷贝函数memcpy(指针1,指针2,以字节为单位的内存长度len),将指针2指向的长度为len的内容以字节为单位复制到指针1指向的空间)

拷贝构造:array(const array& another),将another整体赋值给新array。

(const array&表示这个函数保证接受一个array类型的常量引用(即该array自身而非他的拷贝),常量const保证本函数不修改another)

*注意*:以下两个构造时C++11提供的构造,这属于我们的扩展内容。

移动构造:array(array&& another) noexcept,新array直接窃取another的所有数据。

这是由于array接受了一个&&右值引用,而右值往往即将死亡,他不如直接把他的数据偷过来,直接获得他的维护的底层数组的指针,然后把他的指针置为nullptr,防止他死亡时释放掉我偷来的内存。

noexcept表明这个函数是合理的,不会抛出异常(如果内部因为别的原因抛出异常那么程序将直接被杀掉)。

此为移动构造,避免了复制操作的时间和空间浪费。

初始化列表构造:array(std::initializer_list<T> ini_list)。

我们的自定义数组类型应该尽量在行为上靠近基本类型的数组。

作为基本属组,它的行为是int a[]={1,2,3,4};为了让我们的数组拥有这种行为,应该使用初始化列表。initializer_list,即初始化列表,是C++11提供的新类型,使用{}进行初始化。

(注意这个初始化列表是一种类型,与上文无参构造处解释的初始化列表语法有所不同。)

我们在开头#include <initializer_list>,在对array初始化时,隐式构造一个无名initializer_list,然后将它作为初始化参数赋给array,就实现了字面意义上的array<int>a={1,2,3};

其中{1,2,3}隐式构造了一张无名initializer_list,然后它被作为参数传入a的初始化构造中。

函数体中使用const T*指针遍历初始化列表并依次赋给array

(std::initializer_list<T>表示initializer_list内部的数据类型是T,未使用using namespace std时std::用于声明initializer_list的命名空间)

析构函数:~array(),销毁数组释放空间,在主函数结束时自动调用,但在堆上申请的空间需要写入函数体否则无法释放。

		array() : val_size(0), val_capacity(1), val(nullptr) {};//无参构造
		array(const int num) : val_size(0), val_capacity(num) {//提供初始空间的构造
			assert(num > 0);
			val = new T[num];
		}
		array(const int size, T target_val) : val_size(size), val_capacity(size * 2) {//提供初始长度和初值的构造
			assert(size > 0);
			val = new T[size * 2];
			for (int i = 0; i < size; i++)val[i] = target_val;
		}
		array(const T* begin, const T* end) {//从固定长度数组中获取数据进行构造
			assert(begin != nullptr && end != nullptr);
			int size = end - begin;
			val = new T[size * 2];
			val_size = size;
			val_capacity = size * 2;
			memcpy(val, begin, sizeof(T) * size);
		}
		array(const array& another) : val_size(another.val_size), val_capacity(another.val_capacity) {//拷贝构造
			val = new T[another.val_capacity];
			memcpy(val, another.val, sizeof(T) * another.val_size);
		}
		array(array&& another) noexcept : val_size(another.val_size), val_capacity(another.val_capacity) {//移动构造
			val = another.val;
			another.val = nullptr;
		}
		array(const std::initializer_list<T> ini_list) {//初始化列表构造
			int size = ini_list.size();
			val = new T[size * 2];
			int i = 0;
			for (const T* it = ini_list.begin(); it != ini_list.end(); it++)val[i++] = *it;
			val_size = size;
			val_capacity = size * 2;
		}
		~array() {
			delete[]val;
		}
		array& operator=(const array& another) {//重载等于号(它也可以作为构造函数在构造时使用)
			delete[]val;
			val = new T[another.val_capacity];
			memcpy(val, another.val, sizeof(T) * another.val_size);
			val_size = another.val_size;
			val_capacity = another.val_capacity;
			return *this;
		}

整体赋值

作为class类,array应该同时拥有类的性质的数组的性质,那么他就应该可以被视为整体来进行操控。
我们提供三种整体赋值的函数。

重载等于号(复制赋值):array& operator=(const array& another),等于号作为一个的成员函数被我们重新定义,接收另一个array another的常量引用并整体赋值并返回一个自身的常量引用(这是为连等=...=...=...服务的)。

(this指针:返回这个array类的对象本身)

另有函数重载实现移动赋值,与移动构造类似。详见Code。

提供新长度和填充值的内存分配:void assign(const int size, T target_val),效果类似于提供长度和初始值的构造。

数据交换:void swap(array& another),交换两个array的值。

		array& operator=(const array& another) {//重载等于号(它也可以作为构造函数在构造时使用)
			delete[]val;
			val = new T[another.val_capacity];
			memcpy(val, another.val, sizeof(T) * another.val_size);
			val_size = another.val_size;
			val_capacity = another.val_capacity;
			return *this;
		}
		array& operator=(array&& another)noexcept {//移动赋值运算符
			if (this == &another)return *this;
			delete[]val;
			val = another.val;
			val_size = another.val_size;
			val_capacity = another.val_capacity;
			another.val=nullptr;
			return *this;
		}
		void assign(const int size, T target_val) {
	        assert(size > 0);
	        delete[]val;
	        val = new T[size * 2];
        	for (int i = 0; i < size; i++)val[i] = target_val;
        	val_size = size;
        	val_capacity = size * 2;
        }
		void swap(array& another) {
			T* tempval=another.val;
			size_t tempsize = another.val_size,tempcapacity = another.val_capacity;
			another.val = val, another.val_size = val_size, another.val_capacity = val_capacity;
			val = tempval, val_size = tempsize, val_capacity = tempcapacity;
		}

内存管理 

我们提供四个size相关的函数和两个capacity相关的函数维护内存。

获取有效数据长度:size_t size(),返回val_size。

(函数()与{ }之间的const表示函数体内部不进行数据的更改操作)

判断有效空间是否为空:bool empty(),返回val_size是否不等于0,是则false,否则true。

提供新长度的长度重置:void resize(const int size),在size变小时截断后续数据。

提供新长度和填充值的长度重置:void resize(const int size, T target_val),在size变小时截断后续数据,在size变大时在新位置填充target_val。

获取实际空间长度:size_t capacity()const,返回val_capacity。

延长空间:void reserve(const int num),如果申请的新空间小于val_capacity,无事发生,否则申请更大的空间。

		size_t size()const {
			return val_size;
		}
		bool empty()const {
			return val_size ? false : true;
		}
		void resize(const int size) {
			assert(size > 0);
			T* temp = new T[size * 2];
			if (size < val_size)memcpy(temp, val, sizeof(T) * size);
			else memcpy(temp, val, sizeof(T) * val_size);
			delete[]val;
			val = temp;
			val_size = size;
			val_capacity = size * 2;
		}
		void resize(const int size, T target_val) {
			assert(size > 0);
			T* temp = new T[size * 2];
			for (int i = 0; i < size; i++)temp[i] = target_val;
			if (size < val_size)memcpy(temp, val, sizeof(T) * size);
			else memcpy(temp, val, sizeof(T) * val_size);
			delete[]val;
			val = temp;
			val_size = size;
			val_capacity = size * 2;
		}
		size_t capacity()const {
			return val_capacity;
		}
		void reserve(const int num) {
			if (num > val_capacity) {
				T* temp = new T[num];
				memcpy(temp, val, sizeof(T) * val_size);
				delete[]val;
				val = temp;
				val_capacity = num;
			}
		}

数据控制

与固定长度数组不同,我们需要调用成员函数来实现数据增删。

压入新元素:void push_back(T elem),在末尾追加新元素elem,如果有剩余空间大于1则直接写入,否则申请两倍的新空间。

插入新元素:void insert(const int pos, T element),在给定位置插入元素elem。

另有函数重载实现区间插入,详见Code。

删除末元素:void pop_back(),删除最后一个元素。

删除元素:void erase(const int pos),删除指定位置的元素。

另有函数重载实现区间删除,详见Code。

清空元素:void clear(),将val_size置为0。

(memet(指针p,char val,以字节为单位的内存长度len),以字节为单位将val赋给p指向的长度为len的空间)

		void push_back(T elem) {
			if (val_capacity - val_size <= 1)reserve(val_capacity * 2);
			val[val_size++] = elem;
		}
		void insert(const int pos, T elem) {
			assert(pos >= 0 && pos <= val_size);
			if (val_capacity - val_size <= 1)reserve(val_capacity * 2);
			val_size++;
			for (int i = val_size - 1; i > pos; i--) val[i] = val[i - 1];
			val[pos] = elem;
		}
		void insert(const int pos,const T* begin,const T* end) {
			assert(pos >= 0 && pos <= val_size);
			const int len = end - begin;
			if (val_capacity - val_size <= len)reserve(val_capacity * 2);
			val_size += len;
			for (int i = val_size - 1; i > pos+len-1; i--) val[i] = val[i - len];
			for (int j = 0; j < len; j++)val[pos+j] = *(begin + j);
		}
		void pop_back() {
			assert(val_size > 0);
			val_size--;
		}
		void erase(const int pos) {
			assert(pos >= 0 && pos < val_size);
			if(pos != val_size-1)
			for (int i = pos + 1; i < val_size; i++) 
				val[i - 1] = val[i];
			val_size--;
		}
		void erase(const int begin,int end) {
			assert(begin >= 0 && begin < val_size);
			end = end >= val_size ? val_size : end;
			const int len = end - begin;
			if(end < val_size)
				for (int i = begin; i < end; i++) 
					val[i] = val[i + len];
			val_size -= len;
		}
		void clear() {
			memset(val, 0, sizeof(T) * val_size);
			val_size = 0;
		}

数据访问

我们通过编写返回值为引用类型的函数来实现数据的读写功能。

引用返回这个数据本身而非他的拷贝,它是一种比指针更安全的数据传递手段。

以下的所有接口函数都要被声明为const函数,这意味这函数体本身不执行任何的数据变更操作,但这不表示不可以通过接口函数实现数据变更操作。

重载[]号:T& operator[](int pos),为了使我们的数组类有定长数组的特征,重载[]号使arr[]具有作用。[]接收一个int pos,返回pos对应位置的引用。不允许访问负坐标。为了和下一个函数区分,我们允许访问溢出(pos>=size)

成员函数式访问下标:T& at(int pos),上一个函数是模仿固定长度数组的行为,这个函数则提供类的函数式的下标访问,他不允许访问负坐标和访问溢出。

获取头元素:T& front(),获取第一个元素的引用。

获取尾元素:T& back(),获取最后一个元素的引用。

直接获取底部:*T data(),我们运用array类来维护底部的T[]数组,那么用户就应该可以直接获取底部地址。不使用常量修饰而直接暴露接口的行为是极其不安全的,但考虑到这是一篇面向入门读者的文章,我们考虑通过暴露接口来对接一些外部功能(如排序、翻转),而将安全性暂放次要。

		T& operator[](const int pos)const {
			assert(pos >= 0);
			return val[pos];
		}
		T& at(const int pos)const {
			assert(pos >= 0 && pos < val_size);
			return val[pos];
		}
		T& front()const {
			assert(val_size > 0);
			return val[0];
		}
		T& back()const {
			assert(val_size > 0);
			return val[val_size - 1];
		}
		T* data()const {
			return val;
		}

Code

*注意*:代码中对于接收T类型参数的函数,我使用了template <typename V>并使得函数接受了万能引用V&&,如果你对此感兴趣,可以自行学习,否则你可以全部改回T。

#include <initializer_list>
#include <cassert>
#ifndef CUSTOM_DAYNAMIN_ARRAY
#define CUSTOM_DAYNAMIN_ARRAY
namespace custom_dynamic_array {//封装一个命名空间
	template <typename T>
	class array {
	private:
		T* val;
		size_t val_size;
		size_t val_capacity;
	public:
		array() : val_size(0), val_capacity(1), val(nullptr) {};//无参构造
		array(const int num) : val_size(0), val_capacity(num) {//提供初始空间的构造
			assert(num > 0);
			val = new T[num];
		}
		template<typename V>
		array(const int size, V&& target_val) : val_size(size), val_capacity(size * 2) {//提供初始长度和初值的构造
			assert(size > 0);
			val = new T[size * 2];
			for (int i = 0; i < size; i++)val[i] = target_val;
		}
		array(const T* begin, const T* end) {//从固定长度数组中获取数据进行构造
			assert(begin != nullptr && end != nullptr);
			int size = end - begin;
			val = new T[size * 2];
			val_size = size;
			val_capacity = size * 2;
			memcpy(val, begin, sizeof(T) * size);
		}
		array(const array& another) : val_size(another.val_size), val_capacity(another.val_capacity) {//拷贝构造
			val = new T[another.val_capacity];
			memcpy(val, another.val, sizeof(T) * another.val_size);
		}
		array(array&& another) noexcept : val_size(another.val_size), val_capacity(another.val_capacity) {//移动构造
			val = another.val;
			another.val = nullptr;
		}
		array(const std::initializer_list<T> ini_list) {//初始化列表构造
			int size = ini_list.size();
			val = new T[size * 2];
			int i = 0;
			for (const T* it = ini_list.begin(); it != ini_list.end(); it++)val[i++] = *it;
			val_size = size;
			val_capacity = size * 2;
		}
		~array() {
			delete[]val;
		}
		array& operator=(const array& another) {//重载等于号(它也可以作为构造函数在构造时使用)
			delete[]val;
			val = new T[another.val_capacity];
			memcpy(val, another.val, sizeof(T) * another.val_size);
			val_size = another.val_size;
			val_capacity = another.val_capacity;
			return *this;
		}
		array& operator=(array&& another)noexcept {//移动赋值运算符
			if (this == &another)return *this;
			delete[]val;
			val = another.val;
			val_size = another.val_size;
			val_capacity = another.val_capacity;
			another.val = nullptr;
			return *this;
		}
		template<typename V>
		void assign(const int size, V&& target_val) {
			assert(size > 0);
			delete[]val;
			val = new T[size * 2];
			for (int i = 0; i < size; i++)val[i] = target_val;
			val_size = size;
			val_capacity = size * 2;
		}
		void swap(array& another) {
			T* tempval = another.val;
			size_t tempsize = another.val_size, tempcapacity = another.val_capacity;
			another.val = val, another.val_size = val_size, another.val_capacity = val_capacity;
			val = tempval, val_size = tempsize, val_capacity = tempcapacity;
		}
		size_t size()const {
			return val_size;
		}
		bool empty()const {
			return val_size ? false : true;
		}
		void resize(const int size) {
			assert(size > 0);
			T* temp = new T[size * 2];
			if (size < val_size)memcpy(temp, val, sizeof(T) * size);
			else memcpy(temp, val, sizeof(T) * val_size);
			delete[]val;
			val = temp;
			val_size = size;
			val_capacity = size * 2;
		}
		template<typename V>
		void resize(const int size, V&& target_val) {
			assert(size > 0);
			T* temp = new T[size * 2];
			for (int i = 0; i < size; i++)temp[i] = target_val;
			if (size < val_size)memcpy(temp, val, sizeof(T) * size);
			else memcpy(temp, val, sizeof(T) * val_size);
			delete[]val;
			val = temp;
			val_size = size;
			val_capacity = size * 2;
		}
		size_t capacity()const {
			return val_capacity;
		}
		void reserve(const int num) {
			if (num > val_capacity) {
				T* temp = new T[num];
				memcpy(temp, val, sizeof(T) * val_size);
				delete[]val;
				val = temp;
				val_capacity = num;
			}
		}
		template<typename V>
		void push_back(V&& elem) {
			if (val_capacity - val_size <= 1)reserve(val_capacity * 2);
			val[val_size++] = elem;
		}
		template<typename V>
		void insert(const int pos, V&& elem) {
			assert(pos >= 0 && pos <= val_size);
			if (val_capacity - val_size <= 1)reserve(val_capacity * 2);
			val_size++;
			for (int i = val_size - 1; i > pos; i--) val[i] = val[i - 1];
			val[pos] = elem;
		}
		void insert(const int pos, const T* begin, const T* end) {
			assert(pos >= 0 && pos <= val_size);
			const int len = end - begin;
			if (val_capacity - val_size <= len)reserve(val_capacity * 2);
			val_size += len;
			for (int i = val_size - 1; i > pos + len - 1; i--) val[i] = val[i - len];
			for (int j = 0; j < len; j++)val[pos + j] = *(begin + j);
		}
		void pop_back() {
			assert(val_size > 0);
			val_size--;
		}
		void erase(const int pos) {
			assert(pos >= 0 && pos < val_size);
			if(pos != val_size-1)
			for (int i = pos + 1; i < val_size; i++) 
				val[i - 1] = val[i];
			val_size--;
		}
		void erase(const int begin, int end) {
			assert(begin >= 0 && begin < val_size);
			end = end >= val_size ? val_size : end;
			const int len = end - begin;
			if (end < val_size)
				for (int i = begin; i < end; i++)
					val[i] = val[i + len];
			val_size -= len;
		}
		void clear() {
			memset(val, 0, sizeof(T) * val_size);
			val_size = 0;
		}
		T& operator[](const int pos)const {
			assert(pos >= 0);
			return val[pos];
		}
		T& at(const int pos)const {
			assert(pos >= 0 && pos < val_size);
			return val[pos];
		}
		T& front()const {
			assert(val_size > 0);
			return val[0];
		}
		T& back()const {
			assert(val_size > 0);
			return val[val_size - 1];
		}
		T* data()const {
			return val;
		}
	};
}
#endif

测试

#include <iostream>
#include "array.h"
using namespace custom_dynamic_array;//全局使用自己的命名空间;
template <typename T>                //在不全局使用std命名空间时,使用custom_dynamic_array::array<T>....来实现同样效果
void show(::array<T>& arr) {
    if (arr.empty())std::cout << "EMPTY";
    else for (int i = 0; i < arr.size(); i++)std::cout << arr[i] << ' ';
    std::cout << std::endl;
}
int main()
{
    std::cout << "---------------test1---------------" << std::endl;
    array<int>a; show<int>(a);
    array<int>b(5); show<int>(b);
    array<int>c(3, 3); show<int>(c);
    double x[] = { 1.1,2.2,3.3 };
    array<double>d(x, x + 3); show<double>(d);
    array<double>e(d); show(e);
    array<int>f = { 5,6,7,8,9 }; show<int>(f);
    array<int>g = a; show<int>(g);
    std::cout <<"------------------------------------" << std::endl;
    std::cout << "---------------test2---------------" << std::endl;
    a = c; show<int>(a);
    b.assign(6, 2); std::cout << b.size() << std::endl;
    c.assign(8, 2); show<int>(c);
    b.swap(c); show<int>(b);
    std::cout << std::endl;
    std::cout << "------------------------------------" << std::endl;
    std::cout << "---------------test3---------------" << std::endl;
    std::cout << b.size() << std::endl;
    std::cout << (b.empty() ? "YES" : "NO") << std::endl;
    b.resize(10, 5); show<int>(b);
    std::cout << b.capacity() << std::endl;
    b.reserve(50);
    std::cout << b.capacity() << std::endl;
    std::cout << std::endl;
    std::cout << "------------------------------------" << std::endl;
    std::cout << "---------------test4---------------" << std::endl;
    a.push_back(10); a.push_back(10); a.push_back(10); a.push_back(10); show<int>(a);
    a.insert(1, 7); show<int>(a);
    int xx[3] = { 10,11,12 };
    a.insert(1, xx, xx + 2); show<int>(a);
    a.pop_back(); show<int>(a);
    a.erase(2); show<int>(a);
    a.erase(4, 6); show<int>(a);
    a.erase(2, 20); show<int>(a);
    a.clear(); std::cout << (a.empty() ? "YES" : "NO") << std::endl;
    std::cout << std::endl;
    std::cout << "------------------------------------" << std::endl;
    std::cout << "---------------test5---------------" << std::endl;
    show<double>(d);
    d[1] = 8.8; show<double>(d);
    std::cout << d.front() << ' ' << d.back() << std::endl;
    std::cout << "------------------------------------" << std::endl;
    return 0;
}

1fbb4643c56e4108adaf849166b147ac.png

c++ 之动态数组简单介绍 #include <iostream> #include <memory> using namespace std; int main() { typedef int ptr[109]; int *p = new ptr; for(int i = 0; i!= 109; ++i) p[i] = i; for(int i = 0; i!= 109;++i) cout << p[i] << endl; int n; cin >&gt. 阅读详情

相关推荐

C++动态数组详解

在上述代码中,首先从控制台获取数组大小,并使用new操作符分配了指定大小的整型数组内存空间。需要注意的是,在使用动态数组时,一定要小心内存泄漏的问题。如果没有及时释放已经分配的内存空间,会导致程序在运行过程中占用大量的内存,严重影响程序的性能和稳定性。C++中的动态数组是一种非常方便的数据结构,可以在程序运行时根据需要动态地分配内存空间。与静态数组相比,动态数组的大小可变性更强,可以适应不同的存储需求。在C++中,动态数组需要使用new操作符进行内存的分配,然后使用delete操作符释放已分配的内存。

2301_79366332的博客 976

C++数组之动态数组

c++ 数组

weixin_61627067的博客 1万+

c++ 知识点 : 动态定义数组

首先:为什么需要动态定义数组呢? 这是因为,很多情况下,在预编译过程阶段,数组的长度是不能预先知道的,必须在程序运行时动态的给出 但是问题是,c++要求定义数组时,必须明确给定数组的大小,要不然编译通不过 如: int Array[5];正确 int i=5; int Array[i]; 错误 因为在编译阶段,编译器并不知道 i

目前打算换一个工作,有招聘windows c++方向的也欢迎联系,北京、济南 最好 2万+

c++ 动态数组

动态数组 ;使用malloc()和free()动态分配 ;使用new 和delete 两个操作符 ;new/delete 与malloc()/free()的区别。

m0_62870588的博客 2万+

C语言实现动态数组形链表

数组形链表是一种兼具数组和链表特性的一种数据结构。它使用数组来模拟链表的存储方式,使得数据的存取更加灵活。在传统的数组中,每个元素都有一个固定的存储位置,而数组形链表中的每个元素则通过指针连接,因此它们可以在内存中不连续存储。数组形链表定义的关键在于理解元素之间的链接关系如何实现。在数组形链表中,通常会有一个额外的数组用来存储指针,这些指针指向下一个元素的位置。这样的设计使得在遍历数据时,能够像链表一样灵活跳跃到任意位置,同时又能保持数组的快速随机访问特性。// 存储数据的数组。

weixin_32242475的博客 1087

用FPGA在HDMI上显示自定义字符:从COE文件到OSD叠加的保姆级教程

本文详细介绍了如何在FPGA上实现HDMI视频流的OSD字符叠加技术,从COE文件生成到动态区域控制的完整流程。通过Verilog代码示例和实战技巧,帮助开发者掌握字符ROM设计、像素坐标追踪和动态混合等核心技术,适用于视频监控、系统状态显示等应用场景。

weixin_28720767的博客 231

C/C++数据结构之动态数组篇

手把手带你从初识动态数组到手写简单版本的c++vector容器

qq_63883017的博客 1万+

C/C++ 计算程序运行的时间

C/C++计算程序执行时间的方法,精度依次增加,推荐度也依次增加 1.#include <time.h> clock_t start, finish; double process_interval ; start=clock(); process(); //要计时的程序 finish=clock(); process_interval =(double)(finish-star...

stu_shanghui的博客 1020

动态数组的实现(C++)

这是用 C++ 封装的一个简单的动态数组类模板,它由任意多个位置连续的、类型相同的元素组成,其元素个数可在程序运行性改变,与 vector 的工作原理相同。并且使用这个动态数组实现求 2~n 区间之间不确定个数的质数。有需要可以参考,代码如下: // Array.h #pragma once #include <iostream> #include <cassert> ...

柚子树's Blog 7496

群晖Docker安装GitLab

external_url ‘http://lanweixia.synology.me’ 这种情况访问页面的时候加上端口没问题,但是会导致http的克隆地址没有端口。external_url ‘http://lanweixia.synology.me:8000’ 加端口的话,又会导致页面访问不了,Gitlab也一直处于启动状态。​ 完成以后修改docke—>gitlab—>config---->gitlab.rb。就是上面改的端口(docker的端口)首次进入,会设置密码,这个密码就是用户名。

Lim的博客 9108

Quest 3开发第一步:搞定Meta账号登录和Oculus软件连不上设备的那些坑(2024实测)

本文详细介绍了Quest 3开发初期的关键步骤,包括Meta账号注册、Oculus软件安装与设备连接等常见问题的解决方案。针对国内开发者遇到的邮箱限制、验证码接收等难题,提供了实用的应对策略,并分享了开发环境配置和常见问题排查技巧,帮助开发者快速搭建Quest 3开发环境。

weixin_30333885的博客 495

数据结构之动态数组的代码实现(新手小白也能懂/C语言版)

基本数据结构动态数组的代码实现,小白也能轻松拿捏。

morandi666的博客 2226

用 ABAP OAuth 2.0 Client 直连 SAP SuccessFactors:从体系到落地的一条龙实践指南

ABAP SMI允许在后端对外部服务的OData端点进行定义与自定义化配置,并以受信连接的方式暴露给ABAP应用调用。它并不替代OAuth,而是扮演端点与自定义参数的集中化定义者,最终认证依旧由完成。对于需要在ABAP后端发起临时或补充型OData调用的场景,SMI是一个轻量而清晰的集成入口。scope的客户端应用已经完成注册,API DomainCompany ID、证书或密钥都已归档。ABAP的Profile与Client已建立并绑定,OA2C_GRANT可见绿色访问状态。SMI。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 286

「栈」实现LIFO栈(先进后出栈|堆栈|stack)的功能 / 数据结构模版(C++)

​栈,是一种基本的数据结构,也是一种数据适配器。它在底层上以链表方法或动态数组方法实现。本文选择了使用动态数组来实现这种数据结构。

dakingffo的博客 1193

解锁 Bootloader 不再难!HyperOS澎湃系统小米与红米手机通用

必要时,可以在工具右上角安装驱动模块,手动安装驱动。解决方法:确保手机升级到最新稳定版,登录同一个小米账号,并在。新机型解锁时需要等待一段时间,通常为 7 天。如果账号安全评分较低,解锁等待时间会更长。如果解锁失败提示权限不足,说明账号存在安全问题。出现这个错误时,通常是因为网络不稳定。如果解锁次数已满,需要等到下个月。解锁后,手机会重启,首次开机会稍微慢一些,等耐心等待即可。按钮,开始解锁过程,注意:解锁会清除手机内所有数据。7次,开启开发者选项。,右键解压到指定文件夹。,使用小米账号登录。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 7226

【Claude Code】Not logged in 未登录错误解决方案 + /login 认证路径

Claude Code 启动时提示 Not logged in 表示当前会话缺少有效凭证。本文从环境变量、API Key 配置、CI 自动化凭证脚本和系统时钟四个维度,提供完整的认证排查流程与修复方案。

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 894

C/C++语言实现动态数组

C/C++语言实现动态数组C数组的小问题     这里说的动态数组是可以根据需要动态增长占用内存的数组,比如程序初始分配了100个元素,可是运行了一段时间后区区100个空间不能满足了,现在需要400个,怎么办呢;那肯定需要再额外分配300个。     C语言有realloc()函数来解决空间扩充的问题,但是不要忘了realloc可能会迁移内存,很多时候数组中的元素会被其它函数/模块

sparkliang的专栏 1万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

「堆」实现优先队列(priority_queue)的功能 / 数据结构模版(C++)

优先队列,是一种堆结构,按元素的相对大小关系执行出队操作。本文实现了这种数据结构。

dakingffo的博客 1552

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

C语言实现动态数组

指针与动态数组笔记 看公开课的学习笔记,C学习者交流群号 433368826 (我只是群员) 何为数组? 在C语言中,定义一个数组,则是在计算机的内存中占据了一块固定的区域用于存储数据。 定义数组: int array[10] = { 0 }; 我们定义一个一般的一维数组往往有几个参数,以上述例子为例: 数组存储数据的类型 上为 int 整形,也就是数组中单位大小 数组的变量名 上为...

qq_34181098的博客 8365

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C/C++数据结构之动态数组

与前一篇文章中介绍的静态数组不同,动态数组允许我们在运行时根据需要调整其大小。这意味着,数组元素的个数不是在编译时就固定的,而是可以在运行时指定。另外,我们还可以在程序执行过程中动态地添加或删除元素,而无需预先确定数组的最大容量。这种灵活性,使得动态数组非常适合用于那些数据量不确定或会随时间变化的场景。

hope_wisdom的技术博客 2108

「数据结构与算法」什么是数组,如何用C实现一个简单的动态数组

如果你用过R语言,那么一定用过向量,如果用Python,那么一定用过列表。那么问题来了,这两类数据结构有什么区别呢? 为什么Python的列表,支持存放不同类型的数据,而R语言的向量只能放同一个类型的数据呢?还有,为什么R语言的向量化运算函数(如sum, nchar)速度会显著性高于R的循环呢? 对于下面的R代码,那种循环更好呢? # loop 1 a <- c() for ...

xuzhougeng blog 940

数据结构:用C语言实现你的第一个“动态数组”——顺序表

准备好告别编程中那些烦人的“固定大小”数组了吗?本文将带你用C语言亲手打造一个神奇的“动态”数组——顺序表。我们将深入浅出地讲解它的增、删、查、改四大核心操作,揭秘它如何像魔术般自动扩容。无论你是编程新手还是希望夯实基础,这篇博客都将是你征服数据结构的第一步!

persevereX的博客 1154

C/C++实现动态数组

C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量。一旦定义了一个数组,系统将为它分配一个固定大小的空间,以后不能改变,称为静态数组。静态数组存放在:全局变量区、栈。         动态数组,可以随程序需要而重新指定大小。动态数组的内存空间是从堆(heap)上分配(即动态分配)的。是通过执行代码而为其分配存储空间。当程序执行到这些语句时,才为其分配。程序员自己负责释

feifei 2906

C(C++)语言纯手写实现动态数组,及其相关函数(全网最全面/最强)

概述 最近了解到了一点数据结构入门的东西, 在学习后, 根据思路, 设计一个C语言实现的简单的动态数组的实现和相关实现思想,方法的讨论, 以及详细的讲解过程步骤。运用 C++ 的面向对象思想 , 依托C语言结构体实现。 1. 准备知识 malloc() 函数 , relloc() 函数, 指针, struct 结构体 , 一个脑袋, 一双手 本教程适应的C语言版本为C89 以上, 适用的编译器为 VS, VSCode , CLion , CodeBlocks等除了VC++6.0 之外的C++编译器 使用C

HK_HH的博客 2079
上一篇: 「数组」冒泡排序|选择排序|插入排序 / 及优化方案(C++)
下一篇: 「STL::vector」标准库容器:vector(动态数组|向量)介绍(C++)
Daking-
博客等级 码龄3年 912粉丝 70原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值