美文网首页
C语言野指针和非法内存操作分析

C语言野指针和非法内存操作分析

作者: andy_shx | 来源:发表于2020-06-11 20:50 被阅读0次

转载:https://www.cnblogs.com/free-1122/p/9794684.html
一.概念

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

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

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

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

野指针的由来
(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;

}

二.经典错误

非法内存操作分析
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;

}

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

include <stdio.h>

include <malloc.h>

int main()

{

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

printf(s); // OOPS!   

free(s);      

return 0;

}

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

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

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;

}

内存泄漏分析

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;

}

多次释放指针

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函数中释放。多次释放指针会造成异常退出。

使用已经释放的指针

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语言中的交通规则

用malloc申请了内存之后,应该立即检查指针是否我NULl,防止使用值为NULL的指针
int* p = (int*)malloc(5 * sizeof(int));

if( p != NULL)

{

//do something here

}

free(p);

牢记数组的长度,防止数组越界,考虑使用柔性数组
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;

}

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

{

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

free(p);

}

int main()

{

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

f();

free(p);

return 0;

}

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

free指针之后必须立即赋值为NULL
int* p = (int*)malloc(10);

free(p);

p = NULL;

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

相关文章

  • C语言野指针和非法内存操作分析

    转载:https://www.cnblogs.com/free-1122/p/9794684.html一.概念 初...

  • [C]C语言指针

    Blog C语言指针详解 C语言字符串操作 指针的作用 指针是程序数据在内存中的地址,指针变量是用来保存这些地址的...

  • C语言基础及指针③函数与二级指针

    接续上篇 C语言基础及指针②之指针内存分析 在上一篇中 , 我们分析了指针在内存中是怎样存储的 , 以及它是怎样操...

  • C和PHP对比

    PHP是由C语言写的,PHP是脚本语言,C语言是底层语言。两者最大不同之处在于指针。C语言可以通过指针操作内存。其...

  • c++11智能指针父类指针转换为子类指针

    1 C语言指针类型转换 C语言中的指针就是裸指针,裸指针存储是指向计算机内存的某一(起始)地址,通过*取值操作符可...

  • 慕课网-Linux C语言指针与内存-学习笔记

    Linux C语言指针与内存 工具与原理 指针 数组 字符串 堆内存与栈内存 gdb内存调试工具。 C语言中指针的...

  • iOS内存管理

    1、内存管理原因:(1)内存溢出 内存不够用(2)野指针异常 指针操作了不属于自己的存储空间,指针操作已经...

  • 闲聊c/c++: 谈内存(大/小端,高/低字节,高/低地址)

    c/c++和其他语言最大区别在于: 指针 指针就是内存地址,一旦明白了指针与内存地址相关的内容,那理解其他语言,就...

  • Java基础

    Java和C++的区别?a. Java没有指针。c++可以通过指针直接操作内存,但这个动作是危险的,指针引起的操作...

  • java引用类型

    概念 每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“...

网友评论

      本文标题:C语言野指针和非法内存操作分析

      本文链接:https://www.haomeiwen.com/subject/ugyitktx.html