摘要
Go语言在进行指针移动时候,不能像C语言一样使用++的形式进行递增,而需要采用另一种特殊的运算形式。
具体实例
- C语言实现指针对动态数组访问
通过下标对动态数组进行访问
#include <stdio.h>
#include <stdlib.h>
void alloc (int *a,int n){
a=(int*)malloc(n*sizeof(n));
for(int i=0;i<n;i++){
a[i]=i*i+1;
}
for(int i=0;i<n;i++){
printf("a[%d]=%d;\n",i,a[i]);
}
}
访问结果:
通过指针对动态数组进行访问
#include <stdio.h>
#include <stdlib.h>
void alloc (int *a,int n){
a=(int*)malloc(n*sizeof(n));
for(int i=0;i<n;i++){
a[i]=i*i+1;
}
int *p = a;
for(int i=0;i<n;i++){
printf("i=%d,\t *p=%d;\n",i,*p);
p++;
}
}
访问结果:
在C语言中,可以直接利用指针++的方式快速定位到下一个元素。Go语言中,这个方式是行不通的!!!
- Go语言实现指针对动态数组访问
在Golang中,不能直接利用++的形式快速定位到下一个元素,其标识指针地址的uintptr类型,本质上是一个uint类型的数值,uintptr的运算实际上是uint的运算。
直接采用下标访问数组
import "fmt"
func main() {
var a []int
alloc(a,5)
}
func alloc(a []int, n int){
a=make([]int,n)
for i:=0;i<len(a);i++{
a[i]=i*i+1
}
for i:=0;i<n;i++ {
fmt.Printf("a[%d]=%d;\n",i,a[i])
}
}
访问结果
采用指针++的方式访问数组
代码如下
func main() {
var a []int
alloc(a,5)
}
func alloc(a []int, n int){
a=make([]int,n)
for i:=0;i<len(a);i++{
a[i]=i*i+1
}
var ptr *int = &a[0]
for i:=0;i<n;i++ {
fmt.Printf("i=%d, *p=%d;\n",i,*ptr)
p:=uintptr(unsafe.Pointer(ptr))
p++ // p++
ptr=(*int)(unsafe.Pointer(p))
}
}
访问结果:
原因分析,主要原因是因为Go语言中p++不是跳转到与该指针临近的下一个指针,而是真正的指针地址的具体值+1,此时可以把具体的指针打印出来对比。
分析代码如下:
func main() {
var a []int
alloc(a,5)
}
func alloc(a []int, n int){
a=make([]int,n)
for i:=0;i<len(a);i++{
a[i]=i*i+1
}
var ptr *int = &a[0]
for i:=0;i<n;i++ {
fmt.Printf("&a[%d]=%d, p=%d;\n",i,&a[i],ptr)
p:=uintptr(unsafe.Pointer(ptr))
p++ // p++
ptr=(*int)(unsafe.Pointer(p))
}
}
结果显示
解决方式,实际就是进行指针计算时候,用数组元素的实际字节大小替代掉++,具体代码如下所示:
纠正后的程序源代码
func main() {
var a []int
alloc(a,5)
}
func alloc(a []int, n int){
a=make([]int,n)
for i:=0;i<len(a);i++{
a[i]=i*i+1
}
var ptr *int = &a[0]
for i:=0;i<n;i++ {
fmt.Printf("i=%d, *p=%d;\n",i,*ptr)
p:=uintptr(unsafe.Pointer(ptr))
p=p+unsafe.Sizeof(int(0)) // 指针移动
ptr=(*int)(unsafe.Pointer(p))
}
}
修正后的正确结果
结论
利用Go语言的指针访问动态数组不能直接像C语言一样利用++的形式进行数组访问,而需要加上实际的元素大小进行移动。