1. 野指针

(1)指针变量中的值是非法的内存地址,进而形成野指针

(2)野指针不是 NULL 指针,是指向不可用内存地址的指针

(3)NULL 指针并无危害,很好判断,也很好调试

(4)C 语言中无法判断一个指针所保存的地址是否合法

2. 野指针的由来

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

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

(3)使用己经释放过的指针

(4)进行了错误的指针运算

(5)进行了错误的强制类型转换

#include <stdio.h>
#include <malloc.h> int main()
{
int* p1 = (int*)malloc(); //这里只分配40字节
int* p2 = (int*); //该地址是非法的,进行了错误的强制转换
int i = ; for(i = ;i < ; i++)
{
*(p1 + i) = - i; //越界访问,p1所指内存总共才40字节,而这里要写入40*4字节
} free(p1); for(i = ; i < ; i++)
{
p1[i] = p2[i]; //p1越界访问,p2非法内存
} return ;
}

3. 基本原则

(1)绝不返回局部变量和局部数组的地址

(2)任何变量在定义后必须用 0 初始化

(3)字符数组必须确认 0 结束符后才能成为字符串

(4)任何使用与内存操作相关的函数必须指定长度信息

#include <stdio.h>
#include <malloc.h>
#include <string.h> struct Student
{
char* name;
int number;
}; char* func()
{
char p[] = "Hello World!";
return p; //返回栈中数组,这是很危险的。
} void del(char* p)
{
printf("%s\n", p);
free(p); //不符谁申请谁释放的原则!
} int main()
{
struct Student s; //危险,结构体应先初始化,因为结构体里有指针!
char* p = func(); //危险,返回局部的数组地址 //strcpy(s.name, p);//s结构体的name指针是野指针! s.number = ;//合法 p = (char*)malloc(); strcpy(p, "Hello World!");//越界,源字符串比目标内存大! del(p); return ;
}

4.常见内存错误

(1)结构体成员指针未初始化

(2)结构体成员指针未分配足够的内存

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

(4)内存操作越界

#include <stdio.h>
#include <malloc.h> void test(int* p, int size) //对内存操作时,有带长度信息
{
int i = ;
for(i = ; i<size; i++)
{
printf("%d\n",p[i]);
} free(p);//不合符谁申请谁释放原则
//当p指向一个数组时,该操作是非法的,因为
//只能free堆中的内存。
} void func(unsigned int size)
{
int* p = (int*)malloc(size * sizeof(int));
int i = ; if(size % != ) //当size为奇数时会p产生内存泄漏
{
return;
} for(i=; i<size; i++)
{
p[i] = i;
printf("%d\n", p[i]);
} free(p); } int main()
{
int* p = (int*)malloc( * sizeof(int)); test(p, ); //test内部释放了p所指内存,不符合谁申请谁释放原则 free(p); //这里重复释放p,会造成程序崩溃 func(); //参数为奇数,会造成内存泄漏!
func();//正常 return ;
}

5.内存操作的交通规则

(1)动态内存申请之后,应该立即检查指针的值是否为 NULL,防止使用 NULL 指针

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

if (p != NULL){

     //do something here!

}

……

(2)free 指针之后必须立即赋值为 NULL。(如 free(p);p=NULL;)

(3)任何与内存操作相头的函数都必须带长度信息!!!!!!!!!

void printf(int* p, int size) //带长度信息size
{ int i = ;
snprintf(buf,sizeof(buf), "%s\n", "Hello World!"); for(i = ;i< size; i++){ //长度信息size
printf("%s\n",p[i])
}
}

(4)malloc 操作和 free 操作必须匹配,防止内存泄露和多次释放。并且遵循谁申请谁释放的原则。

#include <stdio.h>
#include <malloc.h> struct Demo
{
char* p;
}; int main()
{
struct Demo d1;//结构体(内含指针变量)未被初始化
struct Demo d2; char i = ; for(i='a'; i< 'z'; i++)
{
d1.p[i] = i; //d1.p指针未被初始化,内存空间也未分配
} d2.p = (char*)calloc(, sizeof(char)); printf("%s\n", d2.p); for(i='a'; i< 'z'; i++)
{
d2.p[i] = i;
} free(d2.p); return ;
}

内存错误的本质源于指针保存的地址为非法值(如指针未初始化或指针运算导致的越界)。内存泄漏源于malloc和free不匹配。当malloc次数多于free里产生内存泄漏。反之程序可能崩溃。

参考资料:
www.dt4sw.com
http://www.cnblogs.com/5iedu/category/804081.html

C语言学习笔记--内存操作常见错误的更多相关文章

  1. c语言学习笔记.内存管理.

    内存: 每个程序的内存是分区的:堆区.栈区.静态区.代码区. 1.代码区:放置所有的可执行代码,包括main函数. 2.静态区:存放所有的全局变量和静态变量. 3.栈区:栈(stack),先进后出.存 ...

  2. C语言学习笔记--内存分区

    1. 程序中的栈 1.1 栈的简介 (1)栈中现代计算机程序里最为重要的概念之一 (2)栈在程序中用于维护函数调用上下文 (3)函数中的参数和局部变量存储在栈上 (4)栈保存了一个函数调用所需的维护信 ...

  3. CUBRID学习笔记 7 ms常见错误

    基本不是权限问题,就是dll问题.  重新下载或应用dll注意版本. 权限的问题,先本机测试. 看看在web管理有无问题.  剩下的基本就简单了 欢迎转载 ,转载时请保留作者信息.本文版权归本人所有, ...

  4. c语言学习笔记 - 文件操作

    #include <stdio.h>#include <time.h> int main(void){ time_t t;               //类似于size_t那 ...

  5. Python学习笔记: pip install 常见错误汇总

    本机环境RHEL8, Python3.9 pip install: 无法安装最新版本的包 在pypi上查看pkg的页面,因为有些pip包的版本对特定的python版本有要求 pip install e ...

  6. IOS学习笔记48--一些常见的IOS知识点+面试题

      IOS学习笔记48--一些常见的IOS知识点+面试题   1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...

  7. JVM学习笔记——内存结构篇

    JVM学习笔记--内存结构篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存结构部分 我们会分为以下几部分进行介绍: JVM整体介绍 程序计数器 虚拟机栈 本地方法栈 堆 方法 ...

  8. Go语言学习笔记九: 指针

    Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...

  9. Go语言学习笔记(1)——顺序编程

    Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...

随机推荐

  1. codevs1907 方格取数 3

    «问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.«编程任务:对于给定的方格棋 ...

  2. JNI_Z

    1. ZC: 用到 VC6 ... http://blog.csdn.net/jiangwei0910410003/article/details/17465085 http://blog.csdn. ...

  3. spring boot: java @interface注解

    @interface是用来自定义JAVA Annotation的语法,@interface是用来自定义注释类型的 注释类型的定义跟定义一个接口相似,我们需要在 interface这个关键字前面加上一个 ...

  4. 如何理解python中的if __name__=='main'的作用

    一. 一个浅显易懂的比喻 我们在学习python编程时,不可避免的会遇到if __name__=='main'这样的语句,它到底有什么作用呢? <如何简单地理解Python中的if __name ...

  5. nyojb 2359 巴什博弈变形

    http://acm.nyist.me/JudgeOnline/problem.php?id=2359 2359: 巴什博弈? 时间限制: 1 Sec  内存限制: 30 MB提交: 237  解决: ...

  6. QQ发送位置(高德地图)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout ...

  7. 剑指Offer-翻转单词顺序

    题目描述: 输入一个英文句子,翻转句子中单词的顺序,但单词内字符串的顺序不变.例如输入字符串:"I am a student",则输出"student a am I&qu ...

  8. skynet coroutine 运行笔记

    阅读云大的博客以及网上关于 skynet 的文章,总是会谈服务与消息.不怎么看得懂代码,光读这些文字真的很空洞,不明白说啥.网络的力量是伟大的,相信总能找到一些解决自己疑惑的文章.然后找到了这篇讲解 ...

  9. C++中头文件、源文件之间的区别与联系

    .h头文件和.cpp文件的区别 疑惑1:.h文件能够编写main函数吗? 实验: 编写test.h文件,里面包含main函数 若直接编译g++ test.h -o test,通过file命令 file ...

  10. 使用kaptcha验证码组件操作演示

    1.创建一个Maven项目 2.在pom.xml中引入相关依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmln ...