谈CC++指针精髓
C++指针详解

C++指针详解概述C/C++语⾔之所以强⼤,以及其⾃由性,很⼤部分体现在其灵活的指针运⽤上。
因此,说指针是C/C++语⾔的灵魂⼀点都不为过。
有好的⼀⾯,必然会有坏的⼀⾯,指针的灵活导致了它的难以控制,所以C/C++程序员的很多bug是基于指针问题上的。
今天就对指针进⾏详细的整理。
1、指针是什么?指针是“指向(point to)”另外⼀种类型的复合类型。
复合类型是指基于其它类型定义的类型。
理解指针,先从内存说起:内存是⼀个很⼤的,线性的字节数组。
每⼀个字节都是固定的⼤⼩,由8个⼆进制位组成。
最关键的是,每⼀个字节都有⼀个唯⼀的编号,编号从0开始,⼀直到最后⼀个字节。
程序加载到内存中后,在程序中使⽤的变量、常量、函数等数据,都有⾃⼰唯⼀的⼀个编号,这个编号就是这个数据的地址。
指针的值实质是内存单元(即字节)的编号,所以指针单独从数值上看,也是整数,他们⼀般⽤16进制表⽰。
指针的值(虚拟地址值)使⽤⼀个机器字的⼤⼩来存储,也就是说,对于⼀个机器字为w位的电脑⽽⾔,它的虚拟地址空间是0~[2的w次幂] - 1,程序最多能访问2的w次幂个字节。
这就是为什么xp这种32位系统最⼤⽀持4GB内存的原因了。
因此可以理解为:指针是程序数据在内存中的地址,⽽指针变量是⽤来保存这些地址的变量。
2、变量在内存中的存储举⼀个最简单的例⼦ int a = 1,假设计算机使⽤⽅式存储:内存数据有⼏点规律:计算机中的所有数据都是以⼆进制存储的数据类型决定了占⽤内存的⼤⼩占据内存的地址就是地址值最⼩的那个字节的地址。
现在就可以理解 a 在内存中为什么占4个字节,⽽且⾸地址为0028FF40了。
3、指针对象(变量)⽤来保存指针的对象,就是指针对象。
如果指针变量p1保存了变量 a 的地址,则就说:p1指向了变量a,也可以说p1指向了a所在的内存块,这种指向关系,在图中⼀般⽤箭头表⽰:指针对象p1,也有⾃⼰的内存空间,32位机器占4个字节,64位机器占8个字节。
c 指针概括(学习笔记).

1普通参数与指针参数都占用存储空间(若干字节),char 参数一个字节,char *指针参数也是一个字节;int参数4个字节,int *指针参数也是4个字节2指针参数的存储空间有自己的物理地址,只是指针参数存储空间的内容为是普通参数的物理地址而已。
3指针定义后不用则罢,使用时之前必须赋值。
4.Int a;Const int * pr=&a; (常量指针)指向常量的指针:定义好指针后,赋值方向限制了,非常量指针双向都可以赋值(*pr、a)。
现在呢,只能通过a赋值,*pr不行了,因为常量不能被再赋值了。
不能修改*pr的值——————Int * const pr;(指针常量)此指针为常量:存储空间里的物理地址是个常量,不能再给给这个存储空间赋别的物理地址了。
但它指向的空间可以是任意赋值。
定义时必须初始化。
将指针的指向范围限制到一个地址。
不能修改pr的值——————Const int * const pr;(指向常量的指针常量)不能修改*pr的值——————不能修改pr的值——————5.定义一个数组后,数组名称即数组的首地址Int a[10],*pr;Pr=a;A[i]这时可以用pr[i]表示,或*pr表示(*pr仅表数组中一个数)但在一个程序中使用*pr了,得同时要使用pr++,再不能使用pr[i]了,因为pr、i 都在递增,乱求了。
7.字符串指针Char a[]=”qsh”;Char *pr=a;Pr=”hello”;Cout< 或者 cout<a的输出值是“qsh”,不是“hello”,因为 pr="hello";只是将pr的地址重新定义了一下,没有改变A,qsh hello 都有各自的内存。
要是cout<<*pr;的话就指出来h,因为pr只代表一个地址。
*pr代表一个字符,因此也可以比较大小,知道=’\0’时,*pr=0Void mystrcpy(char * dest,char * source{while(*dest++=*source++;}字符串定义之后,要改就用strcpy函数、cin函数、cin.getline(函数;字符串指针定义之后,要改就用cin函数、cin.getline(函数、直接将字符串数组赋予。
c语言指针 通俗易懂讲解

c语言指针通俗易懂讲解C语言是一门广泛使用的编程语言,而指针是C语言中的一个重要概念。
指针在C语言中具有非常重要的作用,它能够使我们更灵活地操作内存和数据。
但是,对于初学者来说,指针可能会是一个难以理解的概念。
因此,本文将以通俗易懂的方式解释C语言指针的概念和用法。
首先,我们来解释指针的基本概念。
在C语言中,指针是一个变量,其存储的值是内存地址。
你可以将指针看作是指向内存中某个特定位置的“指针”,通过这个指针,我们可以访问和修改该内存位置上的数据。
这个地址可以是任何数据类型,例如整数、字符、数组等。
那么,我们为什么要使用指针呢?使用指针有很多好处。
首先,通过指针,我们可以节省内存空间。
指针可以传递地址,而不是复制整个数据。
其次,指针能够使我们在函数之间传递数据更加高效。
当我们将指针作为参数传递给函数时,可以直接在函数内部修改传递进来的数据,而无需进行数据的复制。
最后,指针还可以用于动态分配内存,使我们能够更灵活地管理和操作内存。
接下来,我们来看一些指针的常见用法。
首先是指针的声明和初始化。
要声明一个指针变量,我们需要在变量前面加上“*”符号。
例如,int *ptr; 声明了一个指向整数的指针变量ptr。
要初始化指针,我们可以将其指向一个已存在的变量或者使用动态内存分配函数(例如malloc())进行初始化。
然后是指针的使用。
使用指针时,我们可以通过“*”运算符来访问指针所指向的值。
例如,*ptr将访问ptr指针指向的整数值。
我们还可以使用“&”运算符来获得变量的地址,例如,&num将返回变量num的地址。
另一个常见的指针用法是指针和数组的结合。
在C语言中,数组名称本质上是一个指向数组第一个元素的指针。
因此,我们可以使用指针来遍历数组中的元素,或者通过指针传递数组给函数。
我们还可以使用指针和结构体一起工作。
指针可以指向结构体,这使得我们能够动态创建结构体对象,并在需要时进行修改或访问。
浅谈C语言中指针的概念及基本应用规律

( 1 ) 定义指针后, 必须将其初始 化。 可以用做给指针变 量初
始化 的有变量 的地 址, 另一个指针变量 , 数 组名 , 函数名等 。 需
语句不起作用。 此时, s t r 手 旨 向的存储区里是什么? 我们不知道。
要注意的是动态 内存分配 时, 使用之前将其初始化为N U L L 。 指针在 定义之后, 如果没有 明确 赋值, 那么和其他 变量类 似, 其 内部 的地 址值 是随机 的。 此时指针指 向的空 间中的数据 意义是不可预 测的, 一般 成为野指针。 我们知道在c 语言 中, 指
r e e 或d e l e t e 释放该 内存块 , 否则 , 这块 内存 就不能被 量也必 须为指针, 且 应与返 回值的类 型相同。 指针变 量可 以指 的调用f 再 次使用 , 我们就 说这块 内存泄漏 了。 使 用指针 时, 在赋值 等 向整型变量、 字符 串变 量、 也可以指 向函数 的入 口地址和指针为
函数调用结束后系统会 自动收回 内存 。 的不 同是, 指针数组在指 针的数量 上有所 改变 , 它 由一 个指针 分配局部动态 变量等 , 全局数据 区存放的是静态和全局变量 , 随着程 序的消亡而 自动 演 变到一组同类 指针。
一般 我们 常说的内存 泄漏是指堆 内存 的泄 漏。 堆 ( 2 ) 指针 函数与函数 指针。 指 针函数 是 返回值 为指 针 的函 收收 回内存。 大小任 意的( 内存块的大小可以 数, 指针 函数 打破 了其它高级 语言中的指针、 数组不能作为返 内存 是指 程序从堆 区中分配的,
写程序还是有很大帮助的。 笔者从几个方面来剖析指针 的本质, 并着重围绕指针的一个重要应用一一动态分配内存来谈谈如何回避常见错
C语言中的指针技术

C语言中的指针技术指针技术是C语言中非常重要的概念和特性之一,它允许程序员直接访问内存地址和操作内存中的数据。
指针实际上是一个变量,存储的是另一个变量的地址。
通过指针,程序员可以更高效地管理内存,提高代码的性能和灵活性。
首先,指针提供了直接访问内存地址的能力,这意味着可以在程序中直接操作变量在内存中的位置,而无需通过变量名来访问。
通过指针,可以实现数据的传递和共享,避免在函数调用和数据传递过程中产生额外的开销。
此外,指针还可以实现动态内存分配,程序员可以根据需要在运行时分配和释放内存,更灵活地管理内存空间。
其次,指针可以用来实现数据结构中的链表、树等复杂数据结构。
通过指针的相互引用,可以构建各种复杂的数据结构,实现高效的数据操作和算法。
指针还可以用来实现数据的动态结构,比如链表的插入和删除操作。
指针技术在数据结构和算法中起着至关重要的作用,是程序员必备的技能之一。
另外,指针还可以用来操作数组。
数组名本身就是一个指针常量,指向数组的第一个元素的地址。
通过指针算术运算,可以访问数组中的任意一个元素,实现对数组的灵活操作。
指针还可以用来实现字符串操作,C语言中的字符串本质上是一个字符数组,通过指针可以方便地对字符串进行操作和处理。
除了上述应用,指针还可以用来实现函数指针。
函数指针是指向函数的指针变量,可以将函数作为参数传递给其他函数,实现函数回调和动态调用。
函数指针在一些高级应用中非常有用,比如回调函数、事件处理等。
总的来说,指针技术是C语言中非常重要的概念,掌握指针技术可以帮助程序员更高效地管理内存、实现复杂的数据结构和算法、操作数组和字符串、实现函数回调等功能。
对于想要提升C语言编程水平的程序员来说,深入理解和掌握指针技术是必不可少的。
通过实践和不断学习,可以逐渐掌握指针技术,并运用到实际的编程项目中。
C语言中的指针

【 yw r s CL nug ; o t ; prt n ary fnt n Ke od 】 g ae pi e oea o ;r ;u ci a nr i a o
C语 言是计 算机程序设计语言中专业性最强 的语言之一 , 其 中指针是 C语言中的精髓 ,它在 C语言编程 中被广泛 的使 用 。在某 些场合 ,指针是使 运算 得 以解决 的唯一途径 ,同时 正确 而灵 活的掌握运用它 ,可以提高程序 的运行速度 ,从而 有效地表示和实现复杂数据结构。
WE n IYa g
(ih a iest fS in e n ie rg Zio g6 3 0 Sc u n Unv ri o ce c &E gn en , g n 4 0 0) y
【 btat Acr c a df x l ue f one, i c ladk ypita el s h sec f nu g,stem s A s c 】 or t n ei e s it ad ut n e on s la eesneo l gae i h ot r e l b op r i f s w t Ca
P一一 P+i P—i
P+=i P一=i
/ / 向前 一 个对 象 D指 , / 当前对象后第 i 个对象 / / 当前对象前第 i 个对象 , , D指向当前对象后第 i 个对象 , , D指向当前对象前第 i 个对象
23 两 个 指 针 变 量相 减 .
1 概念
C语言中处理变量 、数组 、函数 、文件时 ,需要由操作系
统 把 这 些 量 调 入 内 存 的 不 同存 储 单 元 中 ,每 个 内存 单 元 都 对
若 两个指针变量指 向同一个数组 的元素 ,则 两指针变量
c语言指针详解通俗易懂
c语言指针详解通俗易懂
C语言中的指针是一个非常重要的概念,它可以让我们直接访问和修改内存中的数据。
指
针是一个变量,它存储了一个内存地址,这个地址指向了一个特定的内存位置。
在C语言中,我们可以使用“&”符号来获取一个变量的地址,而使用“*”符号来访问指针所指向的内存位置。
例如,如果我们有一个变量“a”,我们可以使用“&a”来获取它的地址,
然后使用“*”符号来访问这个地址所指向的内存位置,如“*(&a)”就是访问变量“a”的值。
指针还可以用于动态内存分配,这意味着我们可以在程序运行时动态地分配内存。
例如,我们可以使用“malloc”函数来分配一块指定大小的内存,然后使用指针来访问这块内存。
指针还可以用于函数参数传递,这可以让我们在函数内部直接修改传入的变量,而不需要返回一个值。
例如,我们可以将一个指向整数的指针作为函数参数传递,然后在函数内部修改这个指针所指向的内存位置的值。
指针是C语言中非常重要的概念,它可以让我们直接访问和修改内存中的数据,动态分配内存,以及在函数内部修改传入的变量。
掌握指针的使用方法,可以让我们编写更加高效、灵活的程序。
c语言指针的用法
c语言指针的用法c语言是一种高级编程语言,它可以直接操作内存中的数据。
指针是c语言中一种特殊的变量,它可以存储另一个变量的地址,也就是内存中的位置。
通过指针,我们可以间接地访问或修改内存中的数据,从而实现更高效和灵活的编程。
本文将介绍c语言指针的基本概念、定义和初始化、运算和应用,以及一些常见的错误和注意事项。
希望本文能够帮助你掌握c语言指针的用法,提高你的编程水平。
指针的基本概念指针是一种数据类型,它可以存储一个地址值,也就是内存中某个位置的编号。
每个变量在内存中都有一个唯一的地址,我们可以用指针来记录这个地址,然后通过这个地址来访问或修改变量的值。
例如,假设有一个整型变量a,它的值为10,它在内存中的地址为1000(为了简化,我们假设地址是十进制数)。
我们可以定义一个指向整型的指针p,并把a的地址赋给p,如下所示:int a =10; // 定义一个整型变量a,赋值为10int*p; // 定义一个指向整型的指针pp =&a; // 把a的地址赋给p这里,&a表示取a的地址,也就是1000。
p = &a表示把1000赋给p,也就是让p指向a。
从图中可以看出,p和a是两个不同的变量,它们占用不同的内存空间。
p存储了a的地址,也就是1000。
我们可以通过p 来间接地访问或修改a的值。
指针的定义和初始化指针是一种数据类型,它需要在使用前进行定义和初始化。
定义指针时,需要指定它所指向的变量的类型。
初始化指针时,需要给它赋一个有效的地址值。
定义指针的一般格式为:type *pointer_name;其中,type表示指针所指向的变量的类型,如int、char、float等;pointer_name表示指针的名称,如p、q、ptr等;*表示这是一个指针类型。
例如:int*p; // 定义一个指向整型的指针pchar*q; // 定义一个指向字符型的指针qfloat*ptr; // 定义一个指向浮点型的指针ptr注意,在定义多个指针时,每个指针前都要加*号,不能省略。
《C语言》指针--ppt课件全文
说明: 这种方法可能会破坏系统的正常
工作状态,因为temp是一个指针变量 b 59
但是在函数中并没有给temp一个确定 的地址,这样它所指向的内存单元是 不可预见的,而对*temp的赋值可能 带来危害
swap2 &a p1
&b p2 随机值 temp
5?
ppt课件
11
例 6. 3 ③ #include <stdio.h> void swap3( int *p1, int *p2) { int *p;
p
*p = 12 ; printf (“%d\n” , *p ) ;
对a 重新赋值 等价于 a=12
2. & 与*
p =ห้องสมุดไป่ตู้&a ;
1010 152 a
&*p &(*p) &a *&a *(&a) *p a
ppt课件
6
3. *与 ++ , - -
int a = 2 , b = 5 , c , d , *p ; (1) p = &a ;
② 形参表列: 即指针变量所指向的函数的形参表列 ③ 格式中的小括号不能省略 2. 应用 (1) 让指针变量指向函数 pt = add ; 因为函数名为函数的入口地址, 所以直接将函数名 赋给指针变量即可 (2) 使用指针变量调用函数 格式 : (*指针变量名) ( 实参表列)
ppt课件
17
例 求一维数组中全部元素的和
因此我们可以定义一个指针变量, 让它的值等于 函数的入口地址, 然后可以通过这个指针变量来调用 函数, 该指针变量称为指向函数的指针变量
ppt课件
16
指向函数的指针变量
C语言指针知识点总结
C语⾔指针知识点总结1.指针的使⽤和本质分析(1)初学指针使⽤注意事项1)指针⼀定要初始化,否则容易产⽣野指针(后⾯会详细说明);2)指针只保存同类型变量的地址,不同类型指针也不要相互赋值;3)只有当两个指针指向同⼀个数组中的元素时,才能进⾏指针间的运算和⽐较操作;4)指针只能进⾏减法运算,结果为同⼀个数组中所指元素的下表差值。
(2)指针的本质分析①指针是变量,指针*的意义:1)在声明时,*号表⽰所声明的变量为指针。
例如:int n = 1; int* p = &n;这⾥,变量p保存着n的地址,即p<—>&n,*p<—>n2)在使⽤时,*号表⽰取指针所指向变量的地址值。
例如:int m = *p;②如果⼀个函数需要改变实参的值,则需要使⽤指针作为函数参数(传址调⽤),如果函数的参数数据类型很复杂,可使⽤指针代替。
最常见的就是交换变量函数void swap(int* a, int* b)③指针运算符*和操作运算符的优先级相同例如:int m = *p++;等价于:int m= *p; p++;2.指针和数组(1)指针、数组、数组名如果存在⼀个数组 int m[3] = {1,2,3};定义指针变量p,int *p = m(这⾥m的类型为int*,&a[0]==>int*)这⾥,其中,&m为数组的地址,m为数组0元素的地址,两者相等,但意义不同,例如:m+1 = (unsigned int)m + sizeof(*m)&m+1= (unsigned int)(&m) + sizeof(*&m)= (unsigned int)(&m) + sizeof(m)m+1表⽰数组的第1号元素,&m+1指向数组a的下⼀个地址,即数组元素“3”之后的地址。
等价操作:m[i]←→*(m+i)←→*(i+m)←→i[m]←→*(p+i)←→p[i]实例测试如下:1 #include<stdio.h>23int main()4 {5int m[3] = { 1,2,3 };6int *p = m;78 printf(" &m = %p\n", &m);9 printf(" m = %p\n", m);10 printf("\n");1112 printf(" m+1 = %p\n", m + 1);13 printf(" &m[2] = %p\n", &m[2]);14 printf(" &m+1 = %p\n", &m + 1);15 printf("\n");1617 printf(" m[1] = %d\n", m[1]);18 printf(" *(m+1) = %d\n", *(m + 1));19 printf(" *(1+m) = %d\n", *(1 + m));20 printf(" 1[m] = %d\n", 1[m]);21 printf(" *(p+1) = %d\n", *(p + 1));22 printf(" p[1] = %d\n", p[1]);2324return0;25 }输出结果为:(2)数组名注意事项1)数组名跟数组长度⽆关;2)数组名可以看作⼀个常量指针;所以表达式中数组名只能作为右值使⽤;3)在以下情况数组名不能看作常量指针:- 数组名作为sizeof操作符的参数- 数组名作为&运算符的参数(3)指针和⼆维数组⼀维数组的指针类型是 Type*,⼆维数组的类型的指针类型是Type*[n](4)数组指针和指针数组①数组指针1)数组指针是⼀个指针,⽤于指向⼀个对应类型的数组;2)数组指针的定义⽅式如下所⽰:int (*p)[3] = &m;②指针数组1)指针数组是⼀个数组,该数组⾥每⼀个元素为⼀个指针;2)指针数组的定义⽅式如下所⽰:int* p[5];3.指针和函数(1)函数指针函数的本质是⼀段内存中的代码,函数的类型有返回类型和参数列表,函数名就是函数代码的起始地址(函数⼊⼝地址),通过函数名调⽤函数,本质为指定具体地址的跳转执⾏,因此,可定义指针,保存函数⼊⼝地址,如下所⽰:int funcname(int a, int b);int(*p)(int a, int b) = funcname;上式中,函数指针p只能指向类型为int(int,int)的函数(2)函数指针参数对于函数int funcname(int a, int b);普通函数调⽤ int funcname(int, int),只能调⽤函数int func(int, int)函数指针调⽤ intname(*func)(int,int),可以调⽤任意int(int,int)类型的函数,从⽽利⽤相同代码实现不同功能,实例测试如下,假设有两个相同类型的函数func1和func2:1int func1(int a, int b, int c)2 {3return a + b + c;4 }56int func2(int a, int b, int c)7 {8return a - b - c;9 }普通函数调⽤和函数指针调⽤⽅式及结果如下所⽰1 printf("普通函数调⽤\n");2 printf("func1 = %d\n", func1(100, 10, 1));3 printf("func2 = %d\n", func2(100, 10, 1));4 printf("\n");56 printf("函数指针调⽤\n");7int(*p)(int, int, int) = NULL;8 p = func1;9 printf("p = %d\n", p(100, 10, 1));10 p = func2;11 printf("p = %d\n", p(100, 10, 1));12 printf("\n");需要注意的是,数组作为函数参数的时候,会变为函数指针参数,即:int funcname( int m[] )<——>int funcname ( int* m );调⽤函数时,传递的是数组名,即funcname(m);(3)回调函数利⽤函数指针,可以实现⼀种特殊的调⽤机制——回调函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
指针是C和C++语言编程中最重要的概念之一,也是最容易产生困惑并导致程序出错的问题之一。
利用指针编程可以表示各种数据结构,通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯;并能像汇编语言一样处理内存地址,从而编出精练而高效的程序。
指针极大地丰富了C和C++语言的功能。
在本文中,主要分两部分对指针进行讨论。
首先,基础篇讨论关于指针的内容和运算操作等,可以是读者对指针的知识有一定了解和认识;随后在使用篇中重点讨论指针的各种应用,揭破指针在日常编程中的精髓,从而使读者能够真正地了解、认识和使用指针。
第一篇:基础篇1.1指针的概念谈到指针,它的灵活性和难控制性让许多程序员谈虎色变;但它的直接操作内存,在数据操作方面有着速度快,节约内存等优点,又使许多C++程序员的深爱不以。
那么指针究竟是怎么样一个概念呢?其实,指针就是一类变量,是一类包含了其他变量或函数的地址的变量。
与其他变量所不同的是,一般的变量包含的是实际的真实的数据,而指针是一个指示器,它告诉程序在内存的哪块区域可以找到数据。
好了,在这里我们可以这样定义指针:指针是一类包含了其他变量或函数的地址的变量,它里面存储的数值被解释成为内存的地址。
1.2指针的内容简单讲,指针有四个方面的内容:即指针的类型,指针所指向的类型,指针的值,指针本身所占有的内存区。
下面我们将分别阐述这些内容。
1.2.1指针的类型从语法的角度看,指针的类型是指把指针声明语句中的指针名字去掉所剩下的部分。
这是指针本身所具有的类型。
例如:1.2.2指针所指向的类型当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么类型来看待。
从语法的角度看,指针所指向的类型是指针声明语句中的指针名字和名字左边的指针声明符*去掉所剩下的部分。
例如:1.2.3指针的值(或称指针所指向的内存区)指针的值或者叫指针所指向的内存区或地址,是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。
在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof (指针所指向的类型)的一片内存区。
以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。
在上例中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?1.2.4指针本身所占有的内存区指针本身所占有的内存区是指针本身占内存的大小,这个你只要用函数sizeof(指针的类型)测一下就知道了。
在32位平台里,指针本身占据了4个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
1.3指针与内存管理利用指针你可以将数据写入内存中的任意位置,但是,一旦你的程序中有一个野指针("wild“pointer),即指向一个错误位置的指针,你的数据就危险了—存放在堆中的数据可能会被破坏,用来管理堆的数据结构也可能会被破坏,甚至操作系统的数据也可能会被修改,有时,上述三种破坏情况会同时发生。
所以合理的正确的分配指针的地址是非常重要的。
1.3.1内存分配的方式内存分配方式有三种:(1)从静态存储区域分配。
内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。
例如全局变量,static变量。
(2)在栈上创建。
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配。
程序在运行的时候用malloc或new 申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。
动态内存的生存期由我们决定,使用非常灵活,但问题也最多,以下我们重点讲解动态内存分配。
1.3.2 malloc/free 的使用要点malloc与free是C/C++语言的标准库函数,它用于申请动态内存和释放内存。
函数malloc的原型如下:void * malloc(size_t size);用malloc申请一块长度为length的整数类型的内存,程序如下:int *ip = (int *) malloc(sizeof(int) * length);我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。
malloc函数返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。
malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
例如int变量在16位系统下是2个字节,在32位下是4个字节;而float 变量在16位系统下是4个字节,在32位下也是4个字节。
这个你可以用sizeof (类型)去测试。
在malloc的“()”中使用sizeof运算符是良好的风格,但要当心有时我们会昏了头,写出 ip = malloc(sizeof(ip))这样的程序来。
函数free的原型如下:void free( void * memblock );为什么free函数不象malloc函数那样复杂呢?这是因为指针p的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。
如果p是NULL指针,那么free对p无论操作多少次都不会出问题。
如果p不是NULL 指针,那么free对p连续操作两次就会导致程序运行错误。
1.3.3 new/delete 的使用要点对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。
对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free.因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete.注意new/delete不是库函数,只是C++的运算符。
我们来看如下例子就知道怎么回事了。
用malloc/free和new/delete如何实现对象的动态内存管理类Object的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。
函数UseMallocFree中,由于malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。
函数UseNewDelete则简单得多。
所以我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete.由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。
new内置了sizeof、类型转换和类型安全检查功能,,对于非内部数据类型的对象而言,new在创建动态对象的同时完成了初始化工作。
new/delete 常使用的方法如下:typeof *ip = new typeof[length];类/结构 *ip = new 类结构;一般释放如下:delete ip;数组的释放如下:delete [] ip;1.3.4内存耗尽怎么办?如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL 指针,宣告内存申请失败。
通常有三种方式处理“内存耗尽”问题。
(1)判断指针是否为NULL,如果是则马上用return语句终止本函数。
例如:(3)为new和malloc设置异常处理函数。
例如Visual C++可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc享用与new相同的异常处理函数。
详细内容请参考C++使用手册。
有一个很重要的现象要告诉大家。
对于32位以上的应用程序而言,无论怎样使用malloc与new,几乎不可能导致“内存耗尽”。
因为32位操作系统支持“虚存”,内存用完了,自动用硬盘空间顶替。
我不想误导读者,必须强调:不加错误处理将导致程序的质量很差,千万不可因小失大。
1.3. 5杜绝“野指针”“野指针”不是NULL指针,是指向“垃圾”内存的指针。
人们一般不会错用NULL指针,因为用if语句很容易判断。
但是“野指针”是很危险的,if语句对它不起作用。
“野指针”的原因主要有如下几种:(1)指针变量没有被初始化。
任何指针变量刚被创建时不会自动成为NULL 指针,它的缺省值是随机的,它会乱指一气。
所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
例如char *ip = NULL;char *ip = new char;(2)指针ip被free或者delete之后,没有置为NULL,让人误以为ip是个合法的指针。
(3)指针操作超越了变量的作用范围。
这种情况让人防不胜防,示例程序如下:函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。
但奇怪的是有些编译器运行这个程序时居然没有出错,这可能与编译器有关。
1.3.6指针参数是如何传递内存的?如果函数的参数是一个指针,不要指望用该指针去申请动态内存。
见如下例子:试图用指针参数申请动态内存毛病出在函数GetMemory中。
编译器总是要为函数的每个参数制作临时副本,指针参数ip的副本是 _ip,编译器使 _ip = ip.如果函数体内的程序修改了_ip的内容,就导致参数ip的内容作相应的修改。
这就是指针可以用作输出参数的原因。
在本例中,_ip申请了新的内存,只是把_ip所指的内存地址改变了,但是ip丝毫未变。
所以函数GetMemory并不能输出任何东西。
事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见如下示例:用指向指针的指针申请动态内存当然,我们也可以用函数返回值来传递动态内存。
这种方法更加简单,见如下示例:用函数返回值来传递动态内存用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return 语句用错了。
这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见如下示例:return语句返回指向“栈内存”的指针最后,根据以上阐述,我们总结如下使用规则供大家参考:【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL.防止使用指针值为NULL的内存。