关于野指针 空指针 通用指针
- 格式:rtf
- 大小:44.70 KB
- 文档页数:2
【C】Re05指针⼀、变量 & 指针变量 = 内存地址 + 存储值指针变量 = 内存地址 + 存储值【变量的内存地址】作⽤:间接访问内存地址内存地址 = 地址编号地址编号:内存中的每个字节唯⼀的编号,从0开始记录,使⽤⼗六进制显⽰可以使⽤指针变量存储变量的地址不同数据类型就有对应的指针的数据类型⼆、使⽤#define _CRT_SECURE_NO_WARNINGS#include <stdlib.h>#include <stdio.h>void pointer () {// 指针变量int * pointer;// 变量int varA = 100;printf("pointer -> x16 %x, x10 %d, x8 %o\n", pointer, pointer, pointer);printf("varA -> %d\n", varA);printf("- - - - - - - - - - - - - - -\n");// 把varA的地址赋值给指针变量pointerpointer = &varA;// 通过指针变量pointer取地址访问varA变量*pointer = 20;printf("pointer -> x16 %x, x10 %d, x8 %o\n", pointer, pointer, pointer);printf("varA -> %d\n", varA);}int main() {pointer();return EXIT_SUCCESS;}输出格式注意:// %p显⽰完整⼗六进制位数, %x只显⽰进制数语法递进:int tf = (*pointer == *&varA); // 0 false, 1 trueint tf2 = (pointer == &varA);int tf3 = (*pointer == varA);printf(" %d\n",tf);printf(" %d\n",tf2);printf(" %d\n",tf3);三、空指针& 野指针空指针定义void nullPointerAndWildPointer () {// 定义⼀个空指针int * nullPointer = NULL;}指向的NULL常量来⾃于STDLIB标准库头⽂件的这⼀段#else#define NULL ((void *)0)#endif#endif最后指向的还是⼀个0⽽已void nullPointerAndWildPointer () {// 定义⼀个空指针int * nullPointer = 0;}实际上不建议直接写0,容易混淆指针变量与变量空指针不能被访问到:void nullPointerAndWildPointer () {// 定义⼀个空指针int * nullPointer = NULL;printf("nullPointer -> %p", *nullPointer);}int main() {nullPointerAndWildPointer();return EXIT_SUCCESS;}因为内存地址编号0 - 255已经被操作系统占⽤了空指针的作⽤:不知道应该对指针定义多少合适时使⽤野指针定义:void nullPointerAndWildPointer () {int * wildPointer = 0xffff;printf("wildPointer -> %p\n", *wildPointer);}指针变量存储了⾮法的、未知的⼀个内存地址,该地址存储的内容将⽆法访问但是允许查看地址void nullPointerAndWildPointer () {// 定义⼀个空指针// int * nullPointer = NULL;// printf("nullPointer -> %p\n", *nullPointer);// 定义⼀个野指针// int * wildPointer = 0xffff;// printf("wildPointer -> %p\n", *wildPointer);int * nullPointer = NULL;printf("nullPointer -> %p\n", nullPointer);int * wildPointer = 0xffff;printf("wildPointer -> %p\n", wildPointer);}int main() {nullPointerAndWildPointer();return EXIT_SUCCESS;}野指针的第⼆种情况:也是⼀样,地址可以访问,但是内部存储的值⽆法访问// 野指针的第⼆种情况int * wildPointer2;printf("wildPointer2 -> %p\n", wildPointer2);// printf("wildPointer2 value -> %d\n", *wildPointer2);四、⽆类型指针和万能指针1、Void类型概述void voidUsage() {// void 是⼀个数据类型,所以也具备对于的指针类型 void *// void 的⽤途是修饰函数返回类型和形参类型}// 形参修饰了void 表⽰该函数不需要参数void noNeedParam( void ) {}2、函数返回类型省略当函数的返回值类型声明的是void时,我们可以省略,不需要return不过不建议这样书写,C++并不⽀持这样的语法aaa () {printf("void返回类型省略的函数调⽤");}int main() {aaa();return EXIT_SUCCESS;}如果函数不需要注⼊任何类型的参数,编写时是可以明确标注void 数据类型即可3、⽆类型指针与万能指针:⽆类型指针可以强转任意类型接收对于的类型的变量地址void noTypePointer() {void * p = NULL;printf("sizeof p = %d\n", sizeof(p)); // 64位 sizeof p = 8 32位 sizeof p = 4int num = 10;p = #// printf("p = %d\n", *p); int指针类型赋值给void指针类型,类型不匹配错误// 使⽤强转来转换指针类型printf("p = %d\n", *(int *)p);}另外可以作为万能指针使⽤:void anyTypePointer() {void * pointer = NULL;int * varA = NULL;char * varB = NULL;// ⼀个是int指针类型⼀个是char指针类型,直接这样赋值不会有语法错误提⽰// 但是在编译执⾏时会有警告提⽰,另外,如果指针调⽤了就会报错。
野指针和空指针声明指针的时候没有初始化,导致指针指向⼀个随机的地址,⽆法使⽤#include<iostream>using namespace std;int main(void){int* p;*p = 200;cout << *p << endl;return0;}p就是⼀个野指针,它指向的是⼀块随机的内存地址,编译器⽆法给⼀个随机的地址赋值200改正#include<iostream>using namespace std;int main(void){int a = 0;int* p=&a;*p = 200;cout << *p << endl;return0;}或者#include<iostream>using namespace std;int main(void){int* p = new(int);*p = 200;cout << *p << endl;delete(p);char ch = getchar();return0;}空指针可以接收各种类型的指针,但是在接受的时候要强转成空指针,⽤的时候再转回来#include<iostream>using namespace std;int main(void){int a = 10;void* p = (void*)&a;cout << *(int*)p << endl;return0;}最左边的*是从地址中取值,(int*)是强转成整形指针空指针不能⽤*直接取值,因为不知道类型,所以编译器不知道从之个地址中取多少长度的数据,所以空指针只能⽤来存(各种数据类型变量类型的)地址,但是取值的话就必须先强转成需要的类型的指针,再⽤*去取值void*类型指针有很多⽤处,因为它可以接收任何类型的指针。
野指针,悬垂指针,垃圾内存,内存“黑洞”野指针,悬垂指针,垃圾内存,内存“黑洞”标签:内存泄漏C++c语言编译器指针2014-07-31 16:53 367人阅读评论(0) 收藏举报分类:C/C++语言(36)作者:疯狂的红豆原文链接:/zlhy_/article/details/8794969野指针,首先它不是NULL指针,其次他指向的内存是不合法的,这个不合法的内存俗称“垃圾”内存。
它产生的原因一个是在free或是delete后,没有及时将指针设置为NULL。
野指针的检测也是很困难的,比如用if(0 == ptr)也是不行的,因为在free或是delete后ptr 并没有被设置为NULL。
关于为什么是(0 == ptr)而不是(ptr == 0),这一点建议去看Effective C++的好像是前5个条款。
悬垂指针和野指针虽然称呼上不同,但是其本质是一致的,成因也是相似的。
当多个指针指向一块内存时,对其中的一个指针施加了free或是delete后,即使把这个指针设置为了NULL,可是其余的指向这块内存的指针也是指向了不合法内存的。
取名为悬垂指针,悬垂引用也是这个道理。
“垃圾”内存这个词是对某个指针说的,说某某指针访问了垃圾内存,就是访问了不合法的内存,也就是指针没有访问这块内存的权限,目前内存的使用权限在于编译器,就像是把一个指针free或是delete后没及时显示的手动的将其设置为NULL。
因为C/C++的机制原因,free和delete只是回收了指针所指向的内存,将这块内存的使用权限收归编译器所有,但是free和delete的内部实现中并没有将指针自动设置为NULL,这就是垃圾内存与野指针的成因。
垃圾内存与野指针,悬垂指针的检测很困难,因为编译器并不知道某个指针所指向的内存是否合法。
尽量避免这些问题,一个方法就是使用智能指针。
关于这一点的讨论与代码示例请参考一篇博文:点击打开连接内存“黑洞”是和上面三个完全不同的概念,在没有对一个指针施加free或是delete前就把这个指针设置为了NULL,这样,这块内存并不属于编译器,他是属于某个变量的合法访问区域,但是这个访问的指针已经不存在了,这样子这块内存就像是一个洞一样,得名曰内存“黑洞”。
c 指针的类型C指针的类型引言:C语言是一种广泛应用的编程语言,而指针则是C语言中非常重要的概念之一。
指针可以说是C语言的精华所在,掌握了指针的类型,对于理解C语言的底层机制和进行高效的编程至关重要。
本文将详细介绍C指针的类型,包括基本指针、空指针、野指针、指向常量的指针、指向函数的指针以及指向指针的指针。
一、基本指针基本指针是C语言中最常用的指针类型。
它可以指向任何类型的数据,包括整型、字符型、浮点型等。
通过基本指针,我们可以通过引用来修改指向的数据,实现对数据的间接操作。
二、空指针空指针是指未被初始化的指针,它不指向任何有效的内存地址。
在C语言中,空指针用NULL来表示。
使用空指针时需要注意,避免对空指针进行解引用操作,否则会导致程序崩溃。
三、野指针野指针是指指向未知或无效内存地址的指针。
野指针的出现通常是由于指针未被初始化或指向的内存已经被释放。
使用野指针会导致程序运行时出现未知错误,因此在使用指针时务必进行初始化。
四、指向常量的指针指向常量的指针是指指针所指向的数据是常量,不能通过指针来修改。
在C语言中,可以使用const关键字来声明指向常量的指针。
指向常量的指针在函数参数传递和数组操作中非常常见,它可以提高程序的安全性和效率。
五、指向函数的指针指向函数的指针是指指针所指向的是函数的地址。
通过函数指针,我们可以实现函数的动态调用和回调机制。
函数指针的类型与函数的声明保持一致,通过函数指针可以调用对应的函数。
六、指向指针的指针指向指针的指针是指指针所指向的是另一个指针的地址。
通过指向指针的指针,我们可以实现对指针的间接操作。
在C语言中,常用于多级指针的传递和动态内存分配等场景。
总结:C指针的类型包括基本指针、空指针、野指针、指向常量的指针、指向函数的指针以及指向指针的指针。
掌握这些指针类型对于理解C语言的底层机制和进行高效的编程非常重要。
使用指针时需要注意避免空指针和野指针的出现,同时合理使用指向常量的指针和指向函数的指针,可以提高程序的安全性和效率。
C语言的简答题包含解答共60道题1. 什么是C语言?◆C语言是一种通用的编程语言,由Dennis Ritchie于1972年开发。
它被广泛用于系统编程、应用程序开发和嵌入式系统等领域。
2. 什么是C语言的注释?◆在C语言中,注释用于添加对代码的解释和说明。
有两种类型的注释:单行注释(//)和多行注释(/* */)。
3. 什么是变量?如何声明变量?◆变量是用于存储数据的标识符。
在C语言中,变量的声明包括变量类型和名称,例如:`int myVariable;`。
4. 什么是数据类型?举例说明几种C语言的数据类型。
◆数据类型定义了变量可以存储的数据类型。
一些C语言的数据类型包括int、float、char、double等。
5. 什么是C语言的关键字?◆关键字是C语言中具有特殊含义的保留字,不能用作变量名。
例如,`if`、`while`、`for`等是关键字。
6. 什么是运算符?举例说明一些C语言的运算符。
◆运算符用于执行各种数学和逻辑操作。
例如,+、-、*、/是算术运算符,==、!=、>、<是比较运算符。
7. 什么是条件语句?举例说明一个C语言的条件语句。
◆条件语句用于根据条件执行不同的代码块。
例如,`if`语句用于在条件满足时执行特定的代码块。
8. 什么是循环语句?举例说明一个C语言的循环语句。
◆循环语句用于多次执行相同的代码块。
例如,`for`循环用于按照特定条件重复执行代码块。
9. 什么是函数?如何声明和定义一个函数?◆函数是可重复使用的代码块,用于执行特定任务。
函数的声明包括函数返回类型、名称和参数列表,例如:`int add(int a, int b);`。
10. 什么是指针?如何声明和使用指针?◆指针是用于存储变量地址的变量。
指针的声明包括指针类型和名称,例如:`int *ptr;`。
要使用指针,可以使用`&`运算符获取变量的地址,使用`*`运算符访问指针指向的值。
11. 什么是C语言中的数组?◆数组是一种用于存储相同数据类型的元素集合的数据结构。
什么是间接引用(indirection)?对已说明的变量来说,变量名就是对变量值的直接引用。
对指向变量或内存中的任何对象的指针来说,指针就是对对象值的间接引用。
如果p是一个指针,p的值就是其对象的地址;*p表示“使间接引用运算符作用于p”,*p的值就是p所指向的对象的值。
*p是一个左值,和变量一样,只要在*p的右边加上赋值运算符,就可改变*p的值。
如果p是一个指向常量的指针,*p就是一个不能修改的左值,即它不能被放到赋值运算符的左边,请看下例:一个间接引用的例子#include <stdio.h>intmain(){int i;int * p ;i = 5;p = & i; / * now * p = = i * // * %Pis described in FAQ VII. 28 * /printf("i=%d, p=%P, * p= %d\n" , i, P, *p);* p = 6; / * same as i = 6 * /printf("i=%d, p=%P, * p= %d\n" , i, P, *P);return 0; / * see FAQ XVI. 4 * / }}上例说明,如果p是一个指向变量i的指针,那么在i能出现的任何一个地方,你都可以用*p代替i。
在上例中,使p指向i(p=&i)后,打印i或*p的结果是相同的;你甚至可以给*p 赋值,其结果就象你给i赋值一样。
一、空指针有时,在程序中需要使用这样一种指针,它并不指向任何对象,这种指针被称为空指针。
空指针的值是NULL,而且NULL在C和C++的定义方式也不一样,甚至不同的编译器也有不同的要求。
例如:define NULL 0 //C的定义方式define NULL (void *)0 //C++的定义方式NULL是在<stddef.h>中定义的一个宏,它的值和任何有效指针的值都不同。
C语⾔指针详解之野指针⽬录指针是什么?怎么表⽰?什么是指针变量?指针类型⼜是什么?指针类型存在的意义野指针是什么?野指针产⽣的原因⼀、指针未初始化⼆、指针越界访问如何避免野指针(野狗)的出现呢?指针运算总结指针是什么?指针只是⼀个名词⽽已,指针就是地址。
我们平时说指针,也可以指指针变量。
怎么表⽰?类型名指针变量 = 地址;例如:int* pa = &a;//我们这⾥的指针类型叫做int*,我读做(yin te 星号)。
//pa是指针变量这段表达式的意思是:定义了⼀个指针变量pa,⾥⾯存放的是a的地址。
⽽这个指针变量的类型为int*。
那下⾯就有同学疑惑了,那什么是指针变量?什么是指针变量?很简单,在之前我们学习了怎么定义整型变量a。
⽐如定义⼀个《整型》《变量a》,然后把a初始化为10。
int a = 10;不过现在变了,我们现在学习了指针。
可以定义⼀个《int*》《变量pa》,然后把pa初识化为&a。
注意:int* 是⼀个类型。
叫做指针类型pa就叫做指针变量int* pa = &a;指针类型⼜是什么?既然变量有不同的类型,⽐如整型,浮点型等。
那么指针也有也有不同的类型。
char *pc = NULL;int *pi = NULL;short *ps = NULL;long *pl = NULL;float *pf = NULL;double *pd = NULL;//NULL为空指针。
这⾥可以看到,指针的定义⽅式是:类型 + * 。
其实:char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
指针类型存在的意义那有这么多的指针的类型,指针类型的意义是什么?我们在这⾥先说两个重要结论:指针的类型决定了指针向前或者向后⾛⼀步(也就是地址+1)有多⼤(能⾛多少个字节)指针的类型决定了,对指针解引⽤的时候有多⼤的权限(能操作⼏个字节)。
关于空指针NULL、野指针、通用指针
首先说一下什么是指针,只要明白了指针的含义,你就明白null的含义了。
假设有语句 int a=10;
那么编译器就在内存中开辟1个整型单元存放变量a,我们假设这个整型单元在内存中的地
址是 0x1000;那么内存0x1000单元中存放了数据10,每次我们访问a的时候,实际上都是
访问的0x1000单元中的10.
现在定义:int *p;
p=&a;
当编译器遇到语句int *p时,它也会在内存中给指针变量p分配一个内存单元,假设这个单
元在内存的编址为0x1003;此时,0x1003中的值是不确定的,(因为我们没有给指针赋值),
当编译器遇到了p=&a时,就会在0x1003单元中保存0x1000,请看,这就是说:(指针变量p
代表的)内存单元0x1003存放了变量a的内存地址!用通俗的话说就是p指向了变量a。
p=NULL,就是说:内存单元0x1003不存放任何变量的内存地址。
删除一个new了的数组。
有必要的话。
比如非标准的类( new CMyClass),在Type *p = new Type[N]; delete []p;的最后最好再加一句: p = NULL
空指针是一个特殊的指针值,也是唯一一个对任何指针类型都合法的指针值。
指针变量具有
空指针值,表示它当时处于闲置状态,没有指向有意义的东西。
空指针用0表示,C语言保
证这个值不会是任何对象的地址。
给指针值赋零则使它不再指向任何有意义的东西。
为了提
高程序的可读性,标准库定义了一个与0等价的符号常量NULL. 程序里可以写 p = 0; 或者 p = NULL; 两种写法都把p置为空指针值。
相对而言,前一种写法更容易使读程序的人
意识到这里是一个指针赋值。
我们印象中C语言的指针都有类型,实际上也存在一种例外。
这里涉及到通用指针,它可以
指向任何类型的变量。
通用指针的类型用(void *)表示,因此也称为void 指针。
int n=3, *p;
void *gp;
gp = &n;
p=(int *)gp1;
野指针,也就是指向不可用内存区域的指针。
通常对这种指针进行操作的话,将会使程序发
生不可预知的错误。
“野指针”不是NULL指针,是指向“垃圾”内存的指针。
人们一般不会错用NULL指针,因
为用if语句很容易判断。
但是“野指针”是很危险的,if语句对它不起作用。
野指针的成
因主要有两种:
一、指针变量没有被初始化。
任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值
是随机的,它会乱指一气。
所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
二、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
别看
free和delete的名字恶狠狠的(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。
通常会用语句if (p != NULL)进行防错处理。
很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。
例:
char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); // p 所指的内存被释放,但是p所指的地址仍然不变
if(p != NULL) // 没有起到防错作用
strcpy(p, “world”); // 出错
另外一个要注意的问题:不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。
指针是个很强大的工具,可是正因为它太强大,所以要操作它不是件易事。
操作不当造成的野指针,甚至会引起系统死机等比较严重的后果。
如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为NULL,如果没有这么做,那么这个指针里的内容是不可预知的,即不知道它指向内存中的哪个空间(即野指针),它有可能指向的是一个空白的内存区域,可能指向的是已经受保护的区域,甚至可能指向系统的关键内存,如果是那样就糟了,也许我们后面不小心对指针进行操作就有可能让系统出现紊乱,死机了。
所以我们必须设定一个空间让指针指向它,或者把指针设为NULL,这是怎么样的一个原理呢,如果是建立一个与指针相同类型的空间,实际上是在内存中的空白区域中开辟了这么一个受保护的内存空间,然后用指针来指向它,那么指针里的地址就是这个受保护空间的地址了,而不是不可预知的啦,然后我们就可以通过指针对这个空间进行相应的操作了;如果我们把指针设为NULL,我们在头文件定义中的 #define NULL 0 可以知道,其实NULL就是表示0,那么我们让指针=NULL,实际上就是让指针=0,如此,指针里的地址(机器数)就被初始化为0了,而内存中地址为0 的内存空间……不用多说也能想象吧,这个地址是特定的,那么也就不是不可预知的在内存中乱指一气的野指针了。
还应该注意的是,free和delete只是把指针所指的内存给释放掉,但并没有把指针本身干掉。
指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。
如果此时不把p设置为NULL,会让人误以为p是个合法的指针。
用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生“野指针”。
内存被释放了,并不表示指针会消亡或者成了NULL指针。
(而且,指针消亡了,也并不表示它所指的内存会被自动释放。
)最后,总结一下野指针的的成因吧: 1、指针变量没有被初始化。
任何指针变量刚被创建时不会自动成为NULL指针,它的默认值是随机的,它会乱指一气。
2、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
3、指针操作超越了变量的作用范围。
这种情况让人防不胜防。