Go语言学习11-数据初始化 作者:huazie
https://cloud.tencent.com/developer/article/2465443?shareByChannel=link
文章详细介绍 Go 数据初始化,包括 new 和 make 函数原理、用法、区别,与字面量对比,内容全面、条理清晰,对理解 Go 有很大帮助。
在计算机内部存储空间,每个储存单元(字节)都有唯一一个地址(编号),这个地址通常是一个二进制编码。指针变量就是用来储存这些地址的。通过地址,我们可以找到所需的变量单元,因此,地址被形象地称为“指针”。简单来说指针就是地址。
我们首先需要用到取地址操作符(&)来取出变量的地址,代码示例
int a = 10;
// 取a的地址并存储到指针变量pa中
int *pa = &a;
printf("变量a的地址为: %p\n", (void *)&a);
printf("指针变量pa存储的地址为: %p\n", (void *)pa);
编辑我们通过取地址操作符(&)拿到的地址是一个数值如:000000549CDFF984,这个数值有时候也是需要存储起来,方便后期使用,我们把这样的地址值存放在指针变量中。代码示例:
int *p = &a;
我们看到p的类型是 int* ,我们该如何理解指针的类型呢?
p左边写的是 int* , * 是在说明pa是指针变量,前面的 int 是在说明pa指向的是整型(int)
类型的对象。
2.我们将地址保存起来,是方便后面拿出来使用的,怎么拿出来使用呢?
我们必须先要学习解引用操作符(*),先来看一段代码
int a = 10;
int *p = &a;
// 通过解引用操作符修改a的值
*p = 0;
printf("修改后a的值为: %d\n", a);
上面代码的 *p的意思就是通过p中存放的地址,找到指向的空间,*p其实就是a变量了;所以*p=0,这个操作符是把a改成了0.等价于a=0;这里是把a的修改交给了p来操作,这样对a的修改,就多了⼀种的途径,写代码就会更加灵活。
3.指针变量到底有多大呢?是根据什么决定的?根据它的类型决定的吗?
先上代码:
// 在不同平台下指针变量大小不同
// 这里只是示意展示获取指针变量大小的方式
int *ptr;
printf("在当前平台下指针变量的大小为: %zu字节\n", sizeof(ptr));
此我们可以知道:指针变量的大小取决于地址的大小
32位平台下地址是32个bit位(即4个字节)
64位平台下地址是64个bit位(即8个字节)
与它指向对象的类型大小无关
先看⼀段代码,调试观察地址的变化。
int arr[] = {1, 2, 3, 4};
int *intPtr = arr;
char *charPtr = (char *)arr;
// int*类型指针移动一步
intPtr++;
printf("int*类型指针移动一步后指向的值为: %d\n", *intPtr);
// char*类型指针移动一步
charPtr++;
printf("char*类型指针移动一步后指向的值为: %d\n", *(int *)(charPtr));
我们可以看出, char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。
这就是指针变量的类型差异带来的变化。
结论:指针的类型决定了指针向前或者向后一步有多大(距离)
先看代码
int a = 10;
// 将int类型变量的地址赋值给void*类型指针
void *voidPtr = &a;
// 以下操作会报错,因为void*类型不能直接进行指针加减和解引用运算
// voidPtr++;
// int value = *(int *)voidPtr;
// 可以先转换为合适的类型再进行操作
int *intPtr = (int *)voidPtr;
printf("通过转换后获取的值为: %d\n", *intPtr);
在上的代码中,将⼀个int类型的变量的地址赋值给⼀个char*类型的指针变量。编译器给出了⼀个警告(如图一),是因为类型不兼容。使void*类型就不会有这样的问题。void*类型的,可以理解为无具体指针类型的指针(或者叫泛型指针)。这种类型指针可以用来接受任意类型地址。但是不能直接进行指针加减整数和解应用的运算。(如图二)。
空指针是一个特殊的指针值,它不指向任何有效的内存地址,用于初始化指针变量,或在解引用指针之前处理指针的错误情况。在C语言中,空指针用NULL表示,它是一个与数值0等价的符号常量。
空指针的应用场景包括:
初始化指针:在定义指针变量时,如果未将指针指向特定的对象,应将指针置空,例如int *ptr = NULL;。
处理指针错误:在解引用指针之前,可以通过检查指针是否为空来避免访问未分配的内存地址,例如使用if (ptr == NULL)来判断。
作为函数参数:当不想传递实际内存地址时,可以使用空指针作为函数参数传递。
释放内存后置空:当使用free或delete释放指针指向的内存后,应将指针置空,以避免野指针的产生,例如delete ptr; ptr = NULL;
野指针是指向内存被释放的内存或者没有访问权限的内存的指针(非法访问)。野指针指向一个不确定的地址空间,或者指向的是一个确定的地址空间的,但引用空间的结果却是不可预知的。与空指针不同,野指针无法通过简单地判断是否为NULL避免,对野指针进行操作很容易造成程序错误,严重时甚至可能引发程序连环式错误,轻者程序结果严重扭曲,重者直接导致程序或者系统崩溃。
野指针的成因主要有三种:
1.指针变量未被初始化。
2.指针释放之后未置空。有时指针在free或delete后未赋值为NULL,便会使人误以为是合法的。free和delete只是把指针所指的内存给释放掉,但并没有把指针本身删除或置空。此时指针指向的就是“垃圾”内存。释放后的指针应立即将指针置为NULL,防止产生“野指针”。
3.指针操作超越了变量的作用域范围。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。