摘要
Go语言和C语言,存在静态和动态两种数组。本文结合Go语言和C语言的代码测试分析这两种语言下的静态与动态数组的区别与联系。
正文
Go语言的数组和C语言的数组在数据结构上是一样的,对于数组 α [ n ] = [ a 0 a 1 ⋯ , a n ] \alpha[n]=[a_{0}a_{1}\cdots,a_{n}] α[n]=[a0a1⋯,an],相同点都是开一个连续的空间存储数据;两种语言编写的静态数组和动态数组在内存分配方式上几乎相同,不过,在动态数组分配上,Go语言的切片实际上是一段内存地址指向的模式,而C语言采用的实际开空间的模式。相对于C语言的动态数据创建模式,Go语言的切片(实现动态数组的方式)除了可以实现动态数组创建,还可以实现多个切片对某个静态数组数据的共享操作。
- 静态数组创建
在静态数组创建方式上,Go语言和C语言是一样的。
Go语言的数组创建源码
func array(){
var b =[4]int{1,2,4,5}
fmt.Printf("addr b=%p\n",&b)
for i:=0;i<len(b);i++{
fmt.Printf("b[%d]=%p\n",i,&b[i])
}
}
C语言的数组创建源码
#include <stdio.h>
#include <stdlib.h>
void array(){
int a[4]={1,3,4,5};
printf("addr a=%p\n",a);
for (int i=0; i<3;i++){
printf("a[%d]=%p\n",i,&a[i]);
}
}
输出数组的地址结果
C和Go在创建静态数组时,内存模型都是一样的,第一个元素的地址就是首地址,同样也是数组变量的实际地址。
- 动态数组创建
在动态数组创建上,C语言采用的动态内存分配的方式,而Go采用的是切片的方式。切片的方式的本质是通过指针在数据上的指向实现创建动态数组。
即,
Go语言
Go语言是通过切片构建动态数组,如下图所示,切片本质上就是一个指向数组的指针和一个确定长度构成的数据结构。
也就是说,切片是一种由指向数组首地址的指针,具体的切片长度(len),以及**基于数组内存空间(最大容量:cap)**构成,最大容量为实际开辟的存储数据的内存空间。
代码验证:
func array(){
b:=[5]int{1,2,4,6,7}
a:=b[:3]
fmt.Printf("len(a)=%d;cap(a)=%d\n",len(a),cap(a))
fmt.Printf("a=%p,addr a=%p,addr a[0]=%p\n",a,&a,&a[0])
}
执行上述代码的结果为:
故,验证切片是由指针,具体的切片长度,以及数组的内存空间构成。从runtime/slice.go文件可以找到slice结构体
与上述验证相符。
Go语言创建动态数组
func dynarray(n int){
a:=make([]int,n);
for i:=0;i<n;i++{
fmt.Printf("a[%d]=%d\n",i,a[i]);
}
}
C语言创建动态数组
#include <stdio.h>
#include <stdlib.h>
void dynarray(size_t n){
int *array;
array=(int*)malloc(n*sizeof(int));
for (int i=0;i<n;i++){
printf("array[%d]=%d;\n",i,array[i]);
}
}
Go语言的切片(slice)和C语言的动态数组,array符号均是指向首个内存地址的指针,而这个指针有一个独立的存储内存,就是指针存储内存。用于存储指向某个内存地址的指针。具体的验证结果如下:
总结
静态数组是一个确定的数据空间,数组变量的地址就是数组的首地址;而动态数组,实际上是赋予一个指针指向一个动态的内存地址区间。