C语言学习笔记--内存操作常见错误
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语言学习笔记--内存操作常见错误的更多相关文章
- c语言学习笔记.内存管理.
内存: 每个程序的内存是分区的:堆区.栈区.静态区.代码区. 1.代码区:放置所有的可执行代码,包括main函数. 2.静态区:存放所有的全局变量和静态变量. 3.栈区:栈(stack),先进后出.存 ...
- C语言学习笔记--内存分区
1. 程序中的栈 1.1 栈的简介 (1)栈中现代计算机程序里最为重要的概念之一 (2)栈在程序中用于维护函数调用上下文 (3)函数中的参数和局部变量存储在栈上 (4)栈保存了一个函数调用所需的维护信 ...
- CUBRID学习笔记 7 ms常见错误
基本不是权限问题,就是dll问题. 重新下载或应用dll注意版本. 权限的问题,先本机测试. 看看在web管理有无问题. 剩下的基本就简单了 欢迎转载 ,转载时请保留作者信息.本文版权归本人所有, ...
- c语言学习笔记 - 文件操作
#include <stdio.h>#include <time.h> int main(void){ time_t t; //类似于size_t那 ...
- Python学习笔记: pip install 常见错误汇总
本机环境RHEL8, Python3.9 pip install: 无法安装最新版本的包 在pypi上查看pkg的页面,因为有些pip包的版本对特定的python版本有要求 pip install e ...
- IOS学习笔记48--一些常见的IOS知识点+面试题
IOS学习笔记48--一些常见的IOS知识点+面试题 1.堆和栈什么区别? 答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制:对于堆来说,释放工作由程序员控制,容易产生memor ...
- JVM学习笔记——内存结构篇
JVM学习笔记--内存结构篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存结构部分 我们会分为以下几部分进行介绍: JVM整体介绍 程序计数器 虚拟机栈 本地方法栈 堆 方法 ...
- Go语言学习笔记九: 指针
Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...
- Go语言学习笔记(1)——顺序编程
Go语言学习笔记这一堆主要是<Go语言编程>(人民邮电出版社)的读书笔记.中间会穿插一些零碎的点,比如源码学习之类的.大概就是这样吧. 1. 顺序编程 1.1 变量 变量的声明: var ...
随机推荐
- codevs1907 方格取数 3
«问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.«编程任务:对于给定的方格棋 ...
- JNI_Z
1. ZC: 用到 VC6 ... http://blog.csdn.net/jiangwei0910410003/article/details/17465085 http://blog.csdn. ...
- spring boot: java @interface注解
@interface是用来自定义JAVA Annotation的语法,@interface是用来自定义注释类型的 注释类型的定义跟定义一个接口相似,我们需要在 interface这个关键字前面加上一个 ...
- 如何理解python中的if __name__=='main'的作用
一. 一个浅显易懂的比喻 我们在学习python编程时,不可避免的会遇到if __name__=='main'这样的语句,它到底有什么作用呢? <如何简单地理解Python中的if __name ...
- nyojb 2359 巴什博弈变形
http://acm.nyist.me/JudgeOnline/problem.php?id=2359 2359: 巴什博弈? 时间限制: 1 Sec 内存限制: 30 MB提交: 237 解决: ...
- QQ发送位置(高德地图)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout ...
- 剑指Offer-翻转单词顺序
题目描述: 输入一个英文句子,翻转句子中单词的顺序,但单词内字符串的顺序不变.例如输入字符串:"I am a student",则输出"student a am I&qu ...
- skynet coroutine 运行笔记
阅读云大的博客以及网上关于 skynet 的文章,总是会谈服务与消息.不怎么看得懂代码,光读这些文字真的很空洞,不明白说啥.网络的力量是伟大的,相信总能找到一些解决自己疑惑的文章.然后找到了这篇讲解 ...
- C++中头文件、源文件之间的区别与联系
.h头文件和.cpp文件的区别 疑惑1:.h文件能够编写main函数吗? 实验: 编写test.h文件,里面包含main函数 若直接编译g++ test.h -o test,通过file命令 file ...
- 使用kaptcha验证码组件操作演示
1.创建一个Maven项目 2.在pom.xml中引入相关依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmln ...