C语言-第32课 - 野指针和内存操作分析

第32课 - 野指针和内存操作分析

一.概念

  1. 初识野指针

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

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

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

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

  1. 野指针的由来

(1)局部指针变量没有被初始化。

例:

#include <stdio.h>

#include <string.h>

struct Student

{

char* name;

int number;

};

int main()

{

struct Student s;

strcpy(s.name, "Delphi Tang"); // OOPS!

s.number = 99;

return 0;

}

(2)使用已经释放过的指针。

例:

#include <stdio.h>

#include <malloc.h>

#include <string.h>

void func(char* p)

{

printf("%s\n", p);

free(p);

}

int main()

{

char* s = (char*)malloc(5);    //内存越界

strcpy(s, "Delphi Tang");

func(s);

printf("%s\n", s); // OOPS!

return 0;

}

使用释放过的指针,很有可能使一些其他程序被莫名的操作。

(3)指针所指向的变量在指针之前被销毁。

例:

#include <stdio.h>

char* func()

{

char p[] = "Delphi Tang";    //保存在栈区,使用之后就会被释放

return p;

}

int main()

{

char* s = func();  //s指向一段被释放了的栈空间。这段空间若是没有被占用,还是会打印Delphi Tang,若是被占用,打印什么,就变得未知了。这时候的s就变成了野指针。

printf("%s\n", s); // OOPS!

return 0;

}

二.经典错误

  1. 非法内存操作分析

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

l 没有为结构体指针分配足够的内存(不能越界)

#include <stdio.h>

#include <malloc.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; // OOPS!

}

//p是未初始化,没有分配地址的指针,也就是野指针,直接给它赋值,是错误的。

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

for(i=0; i<10; i++)

{

d2.p[i] = i; // OOPS!

}

//分配了5个空间,赋值10次。若是这段内存后面的内容没人用,那我们用了也没事。但是,我们若使用了,就会改写了其他的变量。

free(d2.p);

return 0;

}

  1. 内存初始化分析

l 内存分配成功,但是并没有初始化

#include <stdio.h>

#include <malloc.h>

int main()

{

char* s = (char*)malloc(10);

printf(s); // OOPS!

free(s);

return 0;

}

字符串的特点是,以/0结尾,但是我们申请下来的这个字符串是不是以/0结尾确实不一定的。

  1. 内存越界分析--数组越界

#include <stdio.h>

void f(int a[10])

{

int i = 0;

for(i=0; i<10; i++)

{

a[i] = i; // OOPS!

printf("%d\n", a[i]);

}

}

//首先这种方式合理,因为数组在传递而定过程中,会变为指针。但在赋值的时候就出现了错误。

int main()

{

int a[5];

f(a);

return 0;

}

  1. 内存泄漏分析

#include <stdio.h>

#include <malloc.h>

void f(unsigned int size)

{

int* p = (int*)malloc(size*sizeof(int));

int i = 0;

if( size % 2 != 0 )

{

return; // OOPS!这里面的空间没有释放,造成了内存的损失。

}

for(i=0; i<size; i++)

{

p[i] = i;

printf("%d\n", p[i]);

}

free(p);

}

int main()

{

f(9);

f(10);

return 0;

}

设计函数的时候,最好是单入口,单出口。内存泄漏时工程里很容易忽视的。

为了解决这个问题,我们将上面的函数改成单入口,单出口:

#include <stdio.h>

#include <malloc.h>

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);

}

int main()

{

f(9);

f(10);

return 0;

}

  1. 多次释放指针

#include <stdio.h>

#include <malloc.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);

}

int main()

{

int* p = (int*)malloc(5 * sizeof(int));

f(p, 5);

free(p); // OOPS!

return 0;

}

我们这里做一个习惯的要求---谁申请谁释放,main函数中申请的动态空间,就在main函数中释放。多次释放指针会造成异常退出。

  1. 使用已经释放的指针

#include <stdio.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; // OOPS!

}

return 0;

}

释放空间后的指针,就变成了野指针。

三. C语言中的交通规则

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

int* p = (int*)malloc(5 * sizeof(int));

if( p != NULL)

{

//do something here

}

free(p);

  1. 牢记数组的长度,防止数组越界,考虑使用柔性数组

typedef struct _soft_array

{

int len;

int array[];

}SoftArray;

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;

}

  1. 动态申请的操作必须和释放的操作相匹配,方式内存泄漏和多次释放

void f()

{

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

free(p);

}

int main()

{

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

f();

free(p);

return 0;

}

为了解决,我们究竟是在主函数还是子函数中释放,我们可以在子函数中加第三个参数,来判断是否需要释放。

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

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

free(p);

p = NULL;

小结:指针的问题,一般在编译的过程中是找不出来问题的,只有在运行的过程中才会把问题显现出来,所以这里面的一些规则我们是要牢记的,这样可以使我们在工程中,少走很多的弯路。

原文地址:https://www.cnblogs.com/free-1122/p/9794684.html

时间: 2024-10-10 21:17:16

C语言-第32课 - 野指针和内存操作分析的相关文章

野指针与内存操作

1.野指针通常是因为指针变量中保存的值不是一个合法的内存地址而造成的 2.野指针不是NULL指针,是指向不可用内存的指针 3.NULL指针不容易用错,因为if语句很好判断一个指针是不是NULL,C语言中没有任何手段可以判定一个指针是否为野指针 4.(1)局部变量没有被初始化(2)使用已经释放后的指针(3)指针所指向的变量在指针之前被销毁. 5.结构体成员指针未初始化 6.没有为结构体指针分配足够的内存 7.内存分配成功,但并未初始化 8.数组越界 9.内存泄漏,最好单入单出 10.多次指针释放,

第32课 数组指针和指针数组分析

1. 数组的类型 (1)C语言中的数组有自己特定的类型 (2)数组的类型由元素类型和数组大小共同决定.(如int array[5]类型为int[5]) 2. 定义数组类型 (1)C语言中通过typedef为数组类型重命名:typedef type(name)[size]; ①数组类型:如typedef int (AINT5)[5]; typedef float (AFLOAT10)[10]; ②数组定义:AINT5 iArray; AFLOAT10 fArray; 3. 数组指针 (1)数组指针

关于空指针NULL、野指针、通用指针

http://www.cnblogs.com/losesea/archive/2012/11/16/2772590.html 首先说一下什么是指针,只要明白了指针的含义,你就明白null的含义了.假设 有语句 int a=10;那么编译器就在内存中开辟1个整型单元存放变量a,我们假设这个整型单元在内存中的地址是 0x1000:那么内存0x1000单元中存放了数据10,每次我们访问a的时候,实际上都是访问的0x1000单元中的10.现在定义:int *p:                 p=&a

野指针相关总结

小程序如下: 1 void Test(void) 2 { 3 char *str = (char *) malloc(100); 4 strcpy(str, "hello"); 5 free(str); 6 if(str != NULL) 7 { 8 strcpy(str, "world"); 9 printf(str); 10 } 11 } 请问运行Test函数会有什么样的结果?答:篡改动态内存区的内容,后果难以预料,非常危险.因为free(str);之后,str

C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针

(1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放,造成内存泄露,下面的例子就可能造成20个字节的泄露,内存泄露不是一个立即会引发故障的错误,但是 它将消耗系统内存. void function1() { char *pa; pa = (char*)malloc(sizeof(char)*20); if(NULL !=pa) { strcpy(pa,"hello"); printf("pa = %x\n",

Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争

2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在的问题.其最大的特点在于保持较高的运行效率.深入的底层控制和广泛应用范围的同时,解决了传统C语言和C++语言中的内存安全问题.2009年,Mozilla接手Rust项目,创建了以Graydon为首的专业全职开发团队,并且开放了该项目的源代码.2012年1月,第一个面向公众的预览版本--v0.1 发布

C语言指针2(空指针,野指针)

//最近,有朋友开玩笑问 int *p  *是指针还是p是指针还是*p是指针,当然了,知道的都知道p是指针 //野指针----->>>指没有指向一个地址的指针(指针指向地址请参考上一篇文章) //空指针---->>指向空(null)的指针就是空指针 //指针的其他用法,指针可以指向指针,指针可以进行+ - * /运算 /* 特别注意,各个编译器都不相同,这里有一种错误写法,如: int *p,int a=10,b=20; p=&b; *p = &a;    

C语言进阶之路(三)----野指针的产生原因及解决办法

1.会产生野指针的做法 #include <stdio.h> //这就是一种错误的写法 int main(){ int *p = NULL; p = (int *)malloc(4); //释放P所指向的内存空间,但指针变量p仍然留在栈中,成为了野指针 if (p != NULL){ free(p); } if (p != NULL){ free(p); } return 0; } 2.正确的做法: #include <stdio.h>//指针变量和指针所指向的内存变量是两个不同的

OC语言—空指针和野指针

一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针: 1 Student *s1 = NULL; 2 3 Student *s2 = nil; 2.野指针 "野指针"不是NULL指针,是指向"垃圾"内存(不可用内存)的指针.野指针是非常危险的. 二.野指针和空指针例子 接下来用一个简单的例子对比一下野指针和空指针的区别