写在前面的话:
1. 版权声明:本文为博主原创文章,转载请注明出处!
2. 博主是一个小菜鸟,并且非常玻璃心!如果文中有什么问题,请友好地指出来,博主查证后会进行更正,啾咪~~
3. 每篇文章都是博主现阶段的理解,如果理解的更深入的话,博主会不定时更新文章。
4. 本文最后更新时间:2020.7.8
正文开始
关于野指针和内存泄漏
野指针:随机指向一块内存的指针。即没有人为的初始化,而是由系统默认初始化。
野指针的影响:会导致内存泄漏。
例如:
#include <stdio.h>
int main()
{
char *ptr;
printf("Please input ptr = ");
scanf("%s", ptr);
printf("ptr = %s\n", *ptr);
return 0;
}
Please input ptr = cong
段错误
指针ptr没有申请空间,但直接使用了,对应的空间不一定能用。即:定义了一个指针变量,是一个局部变量,但没有初始化,由系统随机初始化。这时给ptr指向的空间赋值,但不一定是系统随机给的地址。
总结一下:
野指针的成因
1. 指针变量没有被初始化
2. 指针p被free或delete后,没有置为NULL,让人误以为p是个合法的指针
3. 指针操作超越了变量的作用范围
造成内存泄漏的原因
1. 指向(访问)了一块没有访问权限的内存(如果正确使用了指针,系统会给指针分配相应的空间,但如果指针指向的内存不是系统分配的,那么会被判定为没有权限)
2. 指向(访问)了一块已经释放的内存
如何避免野指针
避免野指针,最为重要的一点就是要养成良好的编码习惯。
1. 当定义一个指针,且该指针没有指向时,将其置为空。
这里便引入了空指针的概念。
什么是空指针?
If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.( 如果一个空指针常量赋给了一个有类型的指针变量,那么这个指针就叫空指针。它不指向任何的对象或者函数)
也就是说空指针不指向任何对象,空指针的值是NULL。那么NULL又是什么呢?NULL是在“stddef.h”中定义的一个宏,它的值和任何有效指针的值都不同。即:
#define NULL (void *)0 // 代表0地址
0地址的特点:不允许访问,也不允许操作。
如下所示:
#include <stdio.h>
int main()
{
char *ptr = NULL;
printf("Please input ptr = ");
scanf("%s", ptr);
printf("ptr = %s\n", ptr);
return 0;
}
运行结果:
Please input ptr = hello
ptr = (null)
也就是说当一个指针指向空时,就不能对指针赋值或访问。
那么为什么要将没有指向的指针赋值为空呢?请看以下例子:
#include <stdio.h>
int main()
{
char *ptr = NULL;
printf("Please input ptr = ");
scanf("%s", ptr);
while (*ptr != NULL)
{
ptr++;
}
return 0;
}
运行结果:
Please input ptr = hello
段错误
从以上例子可以看出,以后如果出现段错误,我们可以找代码中有没有访问指向空的指针。
将没有指向的指针置为空的好处
1. 不能操作,也不能访问0地址
2. 会出现段错误,好查找调试
2. 当要往指针指向的空间赋值时,先看是否给它分配了合法的空间。
可以使用malloc分配空间。
malloc向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。void* 表示未确定类型的指针。C/C++规定,void* 类型可以强制转换为任何其它类型的指针。
malloc返回值的类型是void *,所以在调用malloc 时要适时地进行类型转换,将void* 转换成所需要的指针类型。
具体代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE sizeof(char) * 100
int main()
{
char *ptr = (char *)malloc(MAX_SIZE); //分配内存
if (NULL == ptr) //检查是否分配成功
{
printf("malloc error!\n");
exit(1);
}
memset(ptr, 0, MAX_SIZE); //清空分配好的空间中的数据
printf("Please input ptr = ");
scanf("%s", ptr);
printf("ptr = %s\n", ptr);
free(ptr); //释放
ptr = NULL; //指针置空
return 0;
}
运行结果:
Please input ptr = hello
ptr = hello
总结一下流程
1. 分配内存空间。
2. 检查分配是否成功。若分配成功,则返回内存的首地址;若分配失败,则返回NULL,并退出程序。
3. 清空分配好的空间的数据,即原来的内存中的数据。(使用malloc或bzero函数)
4. 使用内存。
5. 使用完内存之后,需要释放内存。
6. 对指针置空。若释放内存之后不将指针置空,这时如果继续使用该指针,指针会成为野指针。
在C语言中,指针之间赋值必须是相同指针类型赋值。例如:
以下为相同指针类型赋值:
#include <stdio.h>
int main()
{
int num = 0x12345678;
int *p = #
printf("num = %x\n", *p);
return 0;
}
运行结果:
num = 12345678
以下为不同指针类型赋值:
#include <stdio.h>
int main()
{
char ptr[100];
int num = 0x12345678;
int *p = #
ptr = p;
printf("num = %x\n", ptr);
return 0;
}
编译时报错:
malloc.c: 在函数 ‘main’ 中:
malloc.c:11: 错误:赋值时类型不兼容
从不兼容指针类型赋值可能导致的结果:
1. 取值取不完整
2. 越界
注意:在用malloc分配空间时,可以用宏定义,用宏定义可以提高代码的维护性。
void *可以被看做是一种万能指针,可以接受任何指针类型的值。
它的缺点是:不能对地址指向的空间操作(即不能取值)。