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. 使用struts碰到的错误

    这种错误更有可能url中路径写错了. 而这种情况更有可能使struts.xml写错了.特别要注意action的属性值class的编写是否正确.

  2. SPFA算法O(kE)

    SPFA算法O(kE) Dijkstra和Floyed是不断的试点.Dijkstra试最优点,Floyed试所有点. Bellman-Ford和SPFA是不断的试边.Bellman-Ford是盲目的试 ...

  3. Python—numpy.flatnonzero()

    numpy.flatnonzero(): 该函数输入一个矩阵,返回扁平化后矩阵中非零元素的位置(index) 这是官方文档给出的用法,非常正规,输入一个矩阵,返回了其中非零元素的位置. 1 >& ...

  4. 《Advanced Bash-scripting Guide》学习(十一):shift的用法

    本文所选的例子来自于<Advanced Bash-scripting Gudie>一书,译者 杨春敏 黄毅 Example 4-7 使用shift #!/bin/bash #使用shift ...

  5. PHP用*号替代姓名除第一个字之外的字符

    /* * 作用:用*号替代姓名除第一个字之外的字符 * 参数: * * * 返回值:string */ function starReplace($name, $num = 0) { if ($num ...

  6. @angular/cli项目构建--Dynamic.Form(2)

    form-item-control.service.ts update @Injectable() export class FormItemControlService { constructor( ...

  7. Project://Meeting_Room

    models from django.db import models from django.contrib.auth.models import AbstractUser class UserIn ...

  8. 浅学soap--------4

    引入nusoap Service.php //运行该文件,在网页中wsdl点击,可浏览生成的wsdl代码;网页提供注册的方法 <?php require_once ("nusoap/n ...

  9. 3.4 常用的两种 layer 层 3.7 字体与文本

    3.4 常用的两种 layer 层  //在cocos2d-x中,经常使用到的两种 layer 层 : CCLayer 和 CCLayerColor //CCLayer 的创建 CCLayer* la ...

  10. [转]【技术心得】Last-Modified,Etag,Expire区别

    Last-Modified 是什么 Last-Modified 是 HttpHeader 中的资源的最后修改时间,如果带有 Last-Modified ,下一次发送 Http 请求时,将会发生带 If ...