野指针和内存操作分析

初识野指针:

野指针通常是因为指针变量中保存的值不是一个合法的内存地而造成的

野指针不是NULL指针,是指向不可用内存的指针;

NULL指针不容易用错,因为if语句很好判断一个指针是不是NULL;

C语言中没有任何手段可以判断一个指针是否为野指针;

野指针的由来:

1.局部指针变量没有初始化

#include <stdio.h>
#include <string.h>

struct Student{
	char* name;
	int number;
};

int main()
{
	struct Student s;
	strcpy(s.name, "WGJWGJWGJWGJ"); //OOPS!
	s.name = 99;
	return 0;
}


2.使用已经释放过的指针

#include <stdio.h>
#include <string.h>

void func(char* p)
{
	printf("%s\n", p);
	free(p);
}

int main()
{
	char* s = (char*)malloc(5);
	strcpy(s, "WWWWWWWWWWWWWWW");
	func(s);
	printf("%s\n",s);//OOPS!	

	return 0;
}

3.指针所指向的变量在指针之前被销毁

#include <stdio.h>
#include <string.h>

char* func()
{
	char p[] = "WWWWWWWWWWWWWWWWWW";

	return p;
}

int main()
{
	char* p = func();
	printf("%s\n", p); //OOPS!
	return 0;
}

常见错误:

非法内存操作:

结构体成员指针未初始化;

没有为结构体指针分配足够的内存;

#include <stdio.h>
#include <string.h>

struct Demo{
	int* p;
};

int main()
{
	struct Demo d1;
	struct Demo d2;

	int i = 0;

	for(i=0; i<10; i++){
		d1.p[i] = 0;
	}

	d2.p = (int*)calloc(5, sizeof(int));

	for(i=0; i<10; i++){
		d2.p[i] = i;
	}

	free(d2.p);

	return 0;
}

内存初始化分析:

内存分配成功,但并未初始化

#include <stdio.h>

int main()
{
	char* s = (char*)malloc(10);
	
	printf(s); //s是字符串吗?
	
	free(s);
	
	return 0;	
}

内存越界分析:

数组越界:

#include <stdio.h>

void f(int  a[10])
{
	int i = 0;
	
	for(i=0; i<10; i++){
		a[i] = i;
		printf("%d\n", a[i]);
	}	
}

int main()
{
	int a[5];
	
	f(a); //
	
	return 0;
}

内存泄漏分析:

void f(unsigned int size)
{
	int* p = (int*)malloc(size*sizeof(int));
	int i = 0;
	
	if(size%2 != 0){ //第二个出口,内存没释放
		return;		
	}
	
	for(i=0; i<size; i++){
		p[i] = i;
		printf("%d\n", p[i]);
	}
	
	free(p);
}

改写: 遵循单入口/单出口的原则;

void f(unsigned int size)
{
	int* p = (int*)malloc(size*sizeof(int));
	int i = 0;
	        
	if(size%2 == 0){  //奇数
		for(i=0; i<size; i++){
			p[i] = i;
            printf("%d\n", p[i]);
        }
	}			
	
	free(p);
}

多次指针释放:

#include <stdio.h>

void f(int* p, int size)
{
	int i = 0;
	        
	for(i=0; i<size; i++){
		p[i] = i;
		printf("%d\n", p[i]);
	}			
	
	free(p);
}

void main()
{
	int* p = (int*)malloc(5*sizeof(int));
	
	f(p, 5);
	
	free(p);
	
	return;
}

原则:谁申请的谁释放;

使用已经释放了的内存:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <malloc.h>


void f(int* p, int size)
{
	int i = 0;
	for (i = 0; i < size; i ++ ) {
		printf("%d\n", p[i]);
	}

	free(p);
}

int main()
{
	int* p = (int*)malloc(5 * sizeof(int));
	int i = 0;
	
	f(p, 5);

	for (i = 0; i < 5; i++) {
		p[i] = i;
	}

	getchar();
    return 0;
}

C语言中的交通规则

用malloc申请了内存之后,应该立刻检查指针是否为NULL,防止使用值为NULL的指针

int* p = (int*)malloc(5 * sizeof(int));
if (p != NULL) {
    //do something here!;
}
free(p);

牢记数组的长度,防止数组越界操作,考虑使用柔性数组:

不清楚柔性数组的请自行百度;

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <malloc.h>


typedef struct _soft_array {
	int len;
	int array[];
}SoftArray;

int main()
{
	int i = 0;
	SoftArray* sa = (SoftArray*)malloc(sizeof(SoftArray) + sizeof(int) * 10);
	
	sa->len = 10; //指定柔性数组的长度

	for (i = 0; i < sa->len; i++) {
		sa->array[i] = i + 1;
	}

	printf("%d\n", sizeof(SoftArray)); //4
	printf("%d\n", sizeof(sa)); //4

	getchar();
    return 0;
}

动态申请操作必须和释放操作匹配,防止内存泄漏和多次释放:

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <malloc.h>


void f()
{
	int* p = (int*)malloc(5);

	free(p); //oops!
}

int main()
{
	int* p = (int*)malloc(10);
	f();

	free(p);

	getchar();
    return 0;
}


如果我们需要再f()中free,该怎么办哪?

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <malloc.h>

//toFree:是否要free,避免多次free
void f(int* p, int size, int toFree)
{
	int i = 0;
	for (i = 0; i < size; i++) {
		p[i] = i;
	}

	if (toFree) {
		free(p);
	}
}

int main()
{
	int* p = (int*)malloc(5 * sizeof(int));
//	f(p, 5) ;//error
	f(p, 5, 1);  //
	
	getchar();
    return 0;
}


free指针之后必须立即赋值为NULL

int main()
{
	int* p = (int*)malloc(10);

	free(p);
	//p = NULL;
	
	
	//...
	//...
	//...

	if (p != NULL) { //避免野指针
		int i = 0;
		for (i = 0; i < 5; i++) {
			p[i] = i;
		}
	}
	
	getchar();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值