1.内存越界
直接上例子:
char arr[11]="hello world";
这种情况就是直接下标越界了,因为还会有一个‘\0’没有存入。当数组越界时系统就会自动接着在地址后面继续放入。
此时我们继续写代码:
char* p=malloc(sizeof(int)*11);
strcpy(p,arr)
printf("%s",*p);
我们在堆区开辟一个空间并把它传递给p,然后 输出*p,这个时候如果调试就会报错,因为访问到了系统没分配的地方出的错,未初始化或越界。
2.分配内存为0
char* p=malloc(sizeof(0));
此时为p开辟了一个大小为0的空间,而如果尝试后会发现如果在vs2019上可以复制,并且能输出地址,但是当进行free操作时就会报错,原因和上面一样,不能完全释放掉内存。而我又尝试了dev,发现dev直接就报错了。
3.开辟的内存不为完整大小
什么意思呢就是比如你要开辟一个int型的内存然后你开辟了十个字节
*p=malloc(sizeof(10));
那么意味着前两个空间是可以用的,但是一旦第三个空间被使用,释放的时候就会出现问题,释放两个释放不掉,释放3个释放多了 ,就会导致内存出现问题而报错。
4.多次释放
int* p=(int*)malloc(sizeof(10));
free(p);
free(p);
当我们使用完一块地址要把它释放的时候,我们只需要释放一次即可,释放后指针p就会变为野指针,如果再次释放就相当于将野指针释放掉,这是不允许的
堆空间不允许多次释放
如果我们在第二次释放之前把指针p置空(p=NULL)
在次释放就没问题了(多次释放也没问题)
5.改变指针方向
int* p=(int*)malloc(sizeof(int)*10);
for(int i=0;i<10;i++)
{
*p=i;
p++;
}
free(p);
这串代码就是通过for循环来给p赋初值,乍一看没什么问题,程序也都能正常运行,但是当释放时就出现问题了,因为p指向的地址已经改变,所以释放的地址并不是刚开始开辟的地址,所以会导致错误。
所以我们在使用的时候尽量不要改变指针方向,如果改变一定要在释放前把指针方向改回去,防止出错。(可以做个备份)
6.函数使用一级指针
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void nihao(int* p)
{
*p=10;
}
int main()
{
int a=1;
int* p=&a;
nihao(p);
printf("%d",a);
}
当我们正常使用函数进行地址传递的时候使用的一直都是如上的一级指针进行,这样是可以的,但是如果我们在函数中开辟内存地址,则需要使用二级指针
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void nihao(int* p)
{
p=(int*)malloc(sizeof(int))
}
int main()
{
int* p;
nihao(p);
*p=1;
printf("%d",p);
}
上图是使用一级指针,这样的话就会报错
如图,最上面的p是main函数中的p,我们将p的地址传递给函数中的p(方便起见我们用p1表示)然后开辟了一段空间给p1,此时p1所指的空间已经改变。而函数结束后函数内部的变量就会销毁,也就是说p1并没有把地址返回给p。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void nihao(int** p)
{
*p=(int*)malloc(sizeof(int))
}
int main()
{
int* p;
nihao(p);
*p=1;
printf("%d",&p);
}
这是利用二级指针来运行
因为p1指向的为p,而*p1就代表p,让*p1=malloc就相当于给p开辟了空间,这样就能使用了.
吐槽:就这玩意搞了我好几个小时.....