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. JVM内存管理基础概念

    .内存的不同形态 物理内存 虚拟内存 .内存的使用形式 内核空间 用户空间 .java虚拟机运行时数据划分 PC寄存器:保存当前程序运行时的内存地址. Java栈:总是和线程关联,每个线程拥有一个ja ...

  2. MySql基础学习-总纲

  3. 实现继承+接口继承+虚方法+隐藏方法+this/base+抽象类+密封类/方法+修饰符

    概念: 在上一节课中学习了如何定义类,用类当做模板来声明我们的数据. 很多类中有相似的数据,比如在一个游戏中,有Boss类,小怪类Enemy,这些类他们有很多相同的属性,也有不同的,这个时候我们可以使 ...

  4. 机器学习(六)—随机森林Random Forest

    1.什么是随机采样? Bagging可以简单的理解为:放回抽样,多数表决(分类)或简单平均(回归): Bagging的弱学习器之间没有boosting那样的联系,不存在强依赖关系,基学习器之间属于并列 ...

  5. Python爬虫之利用BeautifulSoup爬取豆瓣小说(三)——将小说信息写入文件

    #-*-coding:utf-8-*- import urllib2 from bs4 import BeautifulSoup class dbxs: def __init__(self): sel ...

  6. 《Advanced Bash-scripting Guide》学习(十六):一个显示输入类型的脚本

    本文所选的例子来自于<Advanced Bash-scripting Gudie>一书,译者 杨春敏 黄毅 function show_input_type() { [ -p /dev/f ...

  7. 在OSX上安装python3使用pip安装Flask

    官方的pypi.python.org可能访问不了,可以先将pip配置为豆瓣的pypi镜像 $ mkdir ~/.pip $ vim ~/.pip/pip.conf [global] timeout = ...

  8. hzau 1209 Deadline(贪心)

    K.Deadline There are N bugs to be repaired and some engineers whose abilities are roughly equal. And ...

  9. 使用for循环添加点击事件时,获取i值的方法

    比如页面上有一个ul,数个li,现在给li添加点击事件. var li = document.getElementsByTagName("li"); for(var i = 0; ...

  10. 服务器端使用DeferredResult异步推送技术

    注意1: org.springframework.web.context.request.async.DeferredResult; 是Spring4.0以后的版本才有的,注意Spring版本,然后添 ...