-
2022-03-29 21:32:22
可变长数组类的实现
成员变量:size表示元素的个数,ptr指针指向动态分配的数组
成员函数:拷贝构造函数,析构函数释放空间
重载运算符 '=' 用于对象间的赋值
重载运算符“[]” 用以支持根据下标访问数组元素
'push_back函数 用于在数组尾部添加一个元素
length 函数 用于返回数组的长度
程序实现如下:
#include <iostream> #include <cstring> using namespace std; class CArray { private: int size;//数组元素的个数 int* ptr;//指向动态分配的数组 public: CArray(int s = 0); //s代表数组元素的个数 CArray(CArray& a); //拷贝构造函数 ~CArray(); //析构函数 void push_back(int v);//用于在数组尾部添加一个元素v CArray& operator = (const CArray& a);//用于对象间的赋值 int length() { return size; } //非引用的函数返回值不可以作为左值使用 int& operator[](int i);//返回值为int 不支持a[i] = 4 }; CArray::CArray(int s) :size(s) { if (s == 0) ptr = NULL; else ptr = new int[s]; } CArray::CArray(CArray& a)//拷贝构造函数的实现 { if (!a.ptr) { ptr = NULL; size = 0; return; } ptr = new int[a.size]; memcpy(ptr, a.ptr, sizeof(int) * a.size); //a.ptr指向的内容拷贝到ptr 拷贝了sizeof(int) * a.size个字节 size = a.size; } CArray::~CArray() { if (ptr) delete[]ptr; } CArray& CArray::operator=(const CArray& a) { if (ptr == a.ptr) //防止a = a这样的赋值导致出错 return *this; if (a.ptr == NULL) { //如果a里面的数组是空的 if (ptr) delete[]ptr; ptr = NULL; size = 0; return *this; } if (size < a.size) { if (ptr) delete[] ptr; ptr = new int[a.size]; } memcpy(ptr, a.ptr, sizeof(int) * a.size); size = a.size; return *this; } int& CArray::operator[](int i) { return ptr[i]; } void CArray::push_back(int v)//在数组尾部添加一个元素 { if (ptr) { int* tmpPtr = new int[size + 1];//重新分配空间 memcpy(tmpPtr, ptr, sizeof(int) * size);//拷贝原数组内容 delete[]ptr; ptr = tmpPtr; } else //数组本来是空的 ptr = new int[1]; ptr[size++] = v;//加入新的数组元素 } int main() { CArray v; for (int i = 0; i < 5; i++) { v.push_back(i); } CArray v2, v3; v2 = v; for (int i = 0; i < v.length(); i++) { cout << v2[i] << " ";//输出0 1 2 3 4 } v2 = v3;//v2空的 for (int i = 0; i < v2.length(); i++) { cout << v2[2] << " "; } cout << endl; v[3] = 100; CArray v4(v); for (int i = 0; i < v4.length(); i++) { cout << v4[i] << " ";//输出0 1 2 100 4 } return 0; }
关于push_back()成员函数的实现
每添加入一个元素便重新分配空间, 这是十分低效的做法,比如可以每次开空间的时候开32个, 每次到32个,时再开32个 ,这样就避免了每次都要重新分配空间,提高效率。
标准模板库中的vector的push_back原理:
vector有预存的内存(capacity),如果存入的元素大于了capacity,就重新分配一个比原来capacity大两倍的内存。
摘自:
更多相关内容 -
C++ 手把手教你实现可变长的数组实现
2020-08-25 08:06:42主要介绍了C++ 手把手教你实现可变长的数组实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
C语言可变长数组
2021-03-15 16:57:07通常,数组变量的长度必须有常量表达式进行定义,但是在C99中,有时候也可以使用非常量表达式 1.代码演示: #include<stdio.h> int main(void){ int i, n; printf("你想颠倒多少个数字?"); scanf("%d",...前言:
通常,数组变量的长度必须有常量表达式进行定义,但是在C99中,有时候也可以使用非常量表达式
1.代码演示:
#include<stdio.h> int main(void){ int i, n; printf("你想颠倒多少个数字?"); scanf("%d",&n); // printf("n=%d\n",n);//调试 int a[n];//C99 only printf("请输入%d个整数:",n); for(i=0;i<n;i++){ scanf("%d",&a[i]);//录入数字 } // printf("n=%d\n",n);//调试 printf("颠倒输出:"); for(i=n-1;i>=0;i--){ printf(" %d",a[i]);//空格分开数字 } printf("\n"); return 0; }
2.运行结果:
你想颠倒多少个数字?12 请输入12个整数:1 2 3 4 5 6 7 8 9 10 11 12 颠倒输出: 12 11 10 9 8 7 6 5 4 3 2 1 -------------------------------- Process exited after 13.18 seconds with return value 0 请按任意键继续. . .
3.原理解释:
- 上面程序的数组a[n]是一个变长数组(VLA),变长数组具有特征如下:
- 变长数组的长度是在程序执行时计算的,而非如常规那样在程序编译时计算
- 主要优点是不必在构造数组时随便给定一个长度,程序在执行过程中可以准确计算出所需元素个数,避免过长(浪费资源)或过短(溢出出错)。
- 变长数组的长度不一定要用变量来指定,任意表达式都可以
int a[3*i+5];
int b[j+k]; - 变长数组的主要限制是它们没有静态存储期限(下面详细讲)
- 变长数组没有初始化式(很自然,没有固定数量自然不能初始化)
- more……
4.静态存储期限
- 变量都是有存储期限的,也就是它们的生命周期,分为自动存储期限和静态存储期限
- 拥有自动存储期限的变量在所属块被执行时获得内存单元,并在块终止时释放内存单元。我们平时随手定义的变量都属于此范畴,生命周期在{块}中。
- 静态存储期限的变量则不需要考虑变量声明的位置,static变量只在程序执行时被初始化一次,然后全程都可以使用,存储位置一直没有改变,但是千万不要以为它和全局变量一样,局部静态存储期限的变量任然是块内可见,并且全局静态变量还限制了只有本源文件内可见,其他源文件不可见。总之,静态存储期限把变量的位置限制固定,但是并没有提升其可见区域。
- 如下是一个静态数组的妙用,仔细体会:
#include<stdio.h> void fillArry(); int main(void){ int i; for(i=0;i<12;i++) { fillArry(); //此处不需要填入任何传递值,也不需要任何返回值,降低了耦合性 } return 0; } void fillArry(){ static int j=0;//用于自增 static int a[12]={0};//用于记住上次调用的赋值 a[j]=j; j++;//j=12时,数组已经赋值完毕 while(j==12){ int i; for(i=0;i<12;i++){ printf("%d ",a[i]); //最后把静态数组输出,以验证每次调用都延续之前的结果 } j++; } }
输出结果:
0 1 2 3 4 5 6 7 8 9 10 11 -------------------------------- Process exited after 0.03233 seconds with return value 0 请按任意键继续. . .
- 以上是静态存储期限的妙用,静态存储期限变量会固定存储位置,这也就意味着,其存储由栈转移到静态存储区,可变长数组的长度都不固定,肯定没法放在固定的位置,这也从一个角度理解了为什么可变长数组不可以由静态存储期限。
- 上面程序的数组a[n]是一个变长数组(VLA),变长数组具有特征如下:
-
Golang可变长数组
2021-11-22 21:36:44可变长数组 代码实现 package zgo_algorithm import ( "fmt" "sync" ) // Array 可变长数组 type Array struct { array []int // 固定大小的数组,用满容量和满大小的切片来代替 len int // 真正长度 cap int...可变长数组
代码实现
package zgo_algorithm import ( "fmt" "sync" ) // Array 可变长数组 type Array struct { array []int // 固定大小的数组,用满容量和满大小的切片来代替 len int // 真正长度 cap int // 容量 lock sync.Mutex // 为了并发安全使用的锁 } // MakeArray 新建一个可变长数组 // 时间复杂度为:O(1),因为分配内存空间和设置几个值是常数时间。 func MakeArray(len, cap int) *Array { s := new(Array) if len > cap { panic("数组的长度不能大于容量") } // 把切片当数组用 array := make([]int, cap, cap) // 元数据 s.array = array s.cap = cap s.len = 0 return s } // Append 增加一个元素 // 添加元素中,耗时主要在老数组中的数据移动到新数组,时间复杂度为:O(n) func (a *Array) Append(element int) { // 并发锁 a.lock.Lock() defer a.lock.Unlock() // 大小等于容量,表示没多余位置了 if a.len == a.cap { // 没容量,数组要扩容,扩容到两倍 newCap := 2 * a.len // 如果之前的容量为0,那么新容量为1 if a.cap == 0 { newCap = 1 } newArray := make([]int, newCap, newCap) // 把老数组的数据移动到新数组 for k, v := range a.array { newArray[k] = v } // 替换数组 a.array = newArray a.cap = newCap } // 把元素放在数组里 a.array[a.len] = element // 真实长度+1 a.len = a.len + 1 } // AppendMany 增加多个元素 func (a *Array) AppendMany(element ...int) { for _, v := range element { a.Append(v) } } // Get 获取某个下标的元素 // 因为只获取下标的值,所以时间复杂度为 O(1) func (a *Array) Get(index int) int { // 越界了 if a.len == 0 || index >= a.len { panic("索引超过了长度") } return a.array[index] } // Len 返回真实长度 // 时间复杂度为 O(1) func (a *Array) Len() int { return a.len } // Cap 返回容量 // 时间复杂度为 O(1) func (a *Array) Cap() int { return a.cap } // 转换为字符串输出,主要用于打印 func (a *Array) ToString() (result string) { result = "[" for i := 0; i < a.Len(); i++ { // 第一个元素 if i == 0 { result = fmt.Sprintf("%s%d", result, a.Get(i)) continue } result = fmt.Sprintf("%s %d", result, a.Get(i)) } result = result + "]" return }
测试
package zgo_algorithm import ( "fmt" "testing" ) func TestArray(t *testing.T) { // 创建一个容量为3的动态数组 a := MakeArray(0, 3) fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", a.ToString()) // 增加一个元素 a.Append(10) fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", a.ToString()) // 增加一个元素 a.Append(9) fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", a.ToString()) // 增加多个元素 a.AppendMany(8, 7) fmt.Println("cap", a.Cap(), "len", a.Len(), "array:",a.ToString()) }
输出结果
=== RUN TestArray cap 3 len 0 array: [] cap 3 len 1 array: [10] cap 3 len 2 array: [10 9] cap 6 len 4 array: [10 9 8 7] --- PASS: TestArray (0.00s) PASS
-
浅谈c语言数组及可变长数组
2020-11-07 00:19:25C99中,程序员声明数组时,数组的维数可以由任一有效的整型表达式确定,包括只在运行时才能确定其值的表达式,这类数组就叫做可变长数组,但是只有局部数组才可以是变长的.可变长数组的维数在数组生存期内是不变的,也...1,了解C89标准和C99中数组的区别
对数组的增强–可变长数组
C99中,程序员声明数组时,数组的维数可以由任一有效的整型表达式确定,包括只在运行时才能确定其值的表达式,这类数组就叫做可变长数组,但是只有局部数组才可以是变长的.可变长数组的维数在数组生存期内是不变的,也就是说,可变长数组不是动态的.可以变化的只是数组的大小.可以使用*来定义不确定长的可变长数组。因此,windows上不支持以下程序(c98?),但linux gcc就支持(c99),仅仅是因为它们的编译器支持不同的标准,下面我们说那个标准不支持更准确:
int b; int a[b]; # c98和c99都不支持这种 void test2(int n) { //scanf("%d", &n); int a[n];# c98不支持,c99支持,谭浩强说支持但实测的不支持,又是标准惹的祸吧 a[0] = 1; printf("%d\n", a[0]); } int main() { int a = 43; test2(a); # c98不支持,c99支持 return 0; }
以下摘自C99可变长数组VLA详解
在程序设计过程中,我们常常遇到需要根据上下文环境来定义数组的情况,在运行期才能确知数组的长度。对于这种情况,C90及C++没有什么很好的办法去解决(STL的方法除外),只能在堆中创建一个内存映像与需求数组一样的替代品,这种替代品不具有数组类型,这是一个遗憾。C99的可变长数组为这个问题提供了一个部分解决方案。可变长数组(variable length array,简称VLA)中的可变长指的是编译期可变,数组定义时其长度可为整数类型的表达式,不再象C90/C++那样必须是整数常量表达式。
2,变长数组很方便,但为什么还是建议有限制地使用?
以下内容整理自C语言为什么不建议把变量作为数组长度
(1)支持VLA(变长数组)的编译器都大多数在栈上分配,但也有在堆上分配的,如armcc的VLA默认是直接使用系统的malloc,free来实现的,据说armcc的VLA用堆还是用栈是可以配置的,我没有深究,若你不确定你的编译器会以何种方式生成VLA代码的时候,不要假定它是基于栈实现的。这是一个比较容易出BUG的点。要避免这种BUG的方式其实也很简单,那就是避免使用VLA。即当要分配的空间长度上界比较小时,你可以使用固定数组大小的形式分配,浪费一点点不用也没关系;当你要分配空间的长度的上界比较大时,直接使用动态分配malloc等函数。(2)因为这里面有太多的坑了,如果你不明白其中原理的话,那么你很容易掉坑里面。变长数组的实现是通过动态设置栈顶来实现的,也就是说这个东西还是在栈上而不是在堆里,这就带来了问题:第一,因为栈的大小是有限制的所以你的每次动态声明相当于调用了一次alloca,不知道这东西的可以自己去查下,其实他们的原理是一样的,通过设置栈顶在栈空间分配一块空间。所以动态数组不能太大。第二,这个东西因为实现在栈上面所以跟栈相关的操作都跟他互相有影响,比如上面提到的alloca,这个东西于动态数组的区别在于作用域,alloca在分配在函数内有效,但是动态数组在最内层括号内有效。但是(这里是重点),因为他们都在栈上面,所以一旦动态数组失效后,在其后分配的alloca也会被free,所以会产生很多不可预料的问题。比如这段代码:
int test() { int a = 10; char *c; { char b[a]; a = 8 * 1024; c = alloca(a); } char d[a]; memset(c, 0, a); memset(d, 2, a); return c[0]; }
编译运行你会得到一个core dump
以下通过在堆上动态申请空间来替代VAL.
malloc(sizeof(Type) * number)…
calloc(sizeof(Type), number)
p = malloc (sizeof (*p) *number) -
C语言面向方法思想的可变长度数组的动态库
2022-04-23 15:05:42最新的可变长度数组实现。使用时要在源文件#include "list.h" 编译时要gcc main.c ./liblist.so 更多的使用方法在README.txt文件中 -
Python从可变长度数组刷新Pyplot线
2021-01-29 15:27:12一些好的答案似乎取决于提前计算数组的最终大小。看起来这应该很简单,而且我是个新手,所以我可能只是搜索了错误的术语。。。在我的问题是:当数组长度未知且随时间变化时,如何让PyPlot刷新源于numpy数组的现有行... -
可变长数组和字典树
2018-09-27 08:43:09可变长数组和字典树Java代码实现。比较容易复制和学习。 -
Java可变长数组,看这篇就对了!
2020-03-12 00:00:00可变长数组设计 可变长数组包含两个组件: ResizableArray ResizableArrayBuffer ResizableArrayBuffer 包含一个大数组。该数组被划分为三个部分。一段用作小数组,一段用作中数组,一段用作大数组。ResizableArray... -
C++可变长数组vector的使用
2021-08-30 14:44:59最近在刷算法,C++里自带的一些容器、函数真是非常简便了。 下面介绍一种可变长的数组,和数组类似,但比数组更强大更方便~~~ -
C语言实现简单可变长数组
2019-11-18 21:16:01可变长只是一种假象,其原理是,当空间不足时,分配新空间,将原空间中的数据转移过去,然后释放旧空间,C++中的vector也是这样的原理,所以,重复的改变空间开销是特别大的,要分配空间,还要转移数据,因此最好一... -
C语言编程技巧:手把手教你学可变长度数组的创建及使用方法
2020-03-30 19:12:37C语言编程技巧:手把手教你学可变长度数组的创建及使用方法问题提出基本函数说明例子说明C语言实现代码总结 问题提出 在C语言编程中,对于普通数组的定义,如定义一个包含10个int类型元素的一维数组a,我们采用下面... -
Java可变长数组概述.pdf
2021-10-04 01:58:41Java可变长数组概述.pdf -
JAVA创建可变长度数组
2019-02-26 14:35:10Java经典编程300例 中的... * 可变长度数组 */ public class UsefulArray { public static Object increaseArray(Object array) { Class<?> clazz = array.getClass();// 获得代表数组的Class对象 ... -
L03_data_structures_lists:链表和可变长度数组
2021-04-17 01:46:20有关线性数据结构,可变长度数组和链接列表的课程代码。 该存储库包含 (可变长度数组)和 (链接列表)数据结构的框架。 在一对夫妇中,学生需要与老师一起开始实施列出的数据结构。 最终的实现将作为家庭作业给... -
scala中的可变长数组
2019-10-24 09:23:57val buffer = ArrayBuffer[T]() 追加方法: += ++= append -
Java可变长度数组
2017-03-22 09:12:33要创建一个可扩展的数组可以使用ArrayList或Vector。ArrayList和Vector类的工作方式都是相同的,只是Vector类中的方法是同步的,而ArrayList中的方法不同步。 ArrayList类仅适用于对象,不适用于原始数据类型。 ... -
C++中 二维可变长数组,vector维度的获取
2021-12-09 15:52:11vector<vector<int>> 对于一些新手来说,很不友好,这里讲解一下如何获取二维可变长数组的维度 -
专题:如何定义一个可变长数组?
2018-03-14 10:19:13与本文章无关的背景(就是想吐吐槽嘛~):昨天刷codeup的时候,碰到字符串的问题,就头皮发麻,然后今天早上吃“老谭酸菜牛肉面”(《谭浩强版c程序设计》)的时候,翻到对于可变长数组定义的方法。 ——————... -
JavaScript可变长数组
2017-11-13 22:18:23var array = [] array[array.length] = 'dsa' for(var i = 0; i ;i ++){ array[array.length] = '我在增长' } -
C++ STL容器之可变长度 数组vector
2019-11-24 19:02:22 -
用c语言实现可变长数组
2015-02-07 11:51:19/*可变长数组的实现*/ #include #include int main(void) { char buf[256]; int size; int *v; int i; printf("input array size>"); fgets(buf,256,stdin); sscanf(buf,"%d",&size); v=(int *)malloc... -
扫盲!Java可变长数组,看这篇就对了!
2020-04-06 18:03:49来自:ImportNew/覃佑桦 | 责编:乐乐 ... 有时我们希望将把数据保存在单个连续的数组中,以便快速、便捷地访问数据,但这需要调整数组大小或者对其...可变长原始类型数组需要自己实现。本文将展示如何实现 Java 可... -
C++ 手把手教你实现可变长的数组
2019-12-01 21:44:0701 实现自定义的可变长数组类型 假设我们要实现一个会自动扩展的数组,要实现什么函数呢?先从下面的main函数给出的实现,看看有什么函数是需要我们实现的。 int main() { MyArray a; // 初始化的数组是空的 for... -
C语言变长数组
2021-05-22 10:56:40C语言变长数组我们知道,传统的C语言是不能像C++那样支持变长数组的,也就是说数组的长度是在编译期就确定下来的,不能在运行期改变。C99标准定义的C语言新特性,新增的一项功能可以允许在C语言中使用变长数组。C99 ... -
C99可变长数组VLA详解
2014-10-12 11:27:03C90及C++的数组对象定义是静态联编的,在编译期就必须给定对象的完整信息。但在程序设计过程中,我们常常遇到需要根据上下文环境来定义数组的情况,在...C99的可变长数组为这个问题提供了一个部分解决方案。 可 -
C语言变长数组使用详解
2021-02-06 14:55:443、用法 :在一个结构体的最后 ,申明一个长度为空的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名 本身不占空间,它只是一个偏移量, 数组名这个符号本身代 ... -
关于可变长度数组VLA初始化所有值为0时可能产生的错误
2021-12-05 20:46:20在支持C99的编译器中,编译代码时不必指定数组的长度,因此下面的代码是合法的。 #include <stdio.h> #include <stdlib.h> int main() { int n; scanf("%d", &n); int num[n]; for (int i = ... -
C语言变长数组讲解
2018-05-08 21:10:31C语言柔性数组讲解 看如下代码: #include&amp;amp;amp;amp;amp;amp;lt;stdio.h&amp;amp;amp;amp;amp;amp;gt; typedef struct _SoftArray{ int len; int array[]; }SoftArray; int main() { ...