当前位置:天才代写 > tutorial > C语言/C++ 教程 > C语言之指针综合谈

C语言之指针综合谈

2017-11-03 08:00 星期五 所属: C语言/C++ 教程 浏览:465

副标题#e#

概述

Joel Spolsky认为,对指针的领略是一种aptitude,不是通过练习就可以到达的。固然如此,我照旧想谈一谈这个C/C++语言中最强劲也是最容易堕落的要素。

鉴于指针和今朝计较机内存布局的关联,许多C语言较量本质的特点都孕育在个中,因此,本篇和第六、第七两篇我都将以指针为主线,团结在实际编程中碰着的问题,来具体谈谈关于指针的几个重要方面。

指针范例的本质阐明

1、指针的本质

指针的本质:一种复合的数据范例。下面我将以下面几个作为例子举办展开阐明:

a)、int *p;

b)、int **p;

c)、int (*parValue)[3];

d)、int (*pFun)();

阐明:

所谓的数据范例就是具有某种数据特征的东东,好比数据范例char,它的数据特征就是它所占据的内存为1个字节, 指针也很雷同,指针所指向的值也占据着内存中的一块地点,地点的长度与指针的范例有关,好比对付char型指针,这个指针占据的内存就是1个字节,因此指针也是一种数据范例,但我们知道指针自己也占据了一个内存空间地点,地点的长度和呆板的字长有关,好比在32位呆板中,这个长度就是4个字节,因此指针自己也同样是一种数据范例,因此,我们说,指针其实是一种复合的数据范例,

好了,此刻我们可以阐明上面的几个例子了。

假设有如下界说:

int nValue; 

那么,nValue的范例就是int,也就是把nValue这个详细变量去掉后剩余的部门,因此,上面的4个声明可以类比举办阐明:

a)、int *

*代表变量(指针自己)的值是一个地点,int代表这个地点内里存放的是一个整数,这两个团结起来,int *界说了一个指向整数的指针,类推如下:

b)、int **

指向一个指向整数的指针的指针。

c)、int (*)[3]

指向一个拥有三个整数的数组的指针。

d)、int (*)()

指向一个函数的指针,这个函数参数为空,返回值为整数。

阐明竣事,从上面可以看出,指针包罗两个方面,一个是它自己的值,是一个内存中的地点;另一个是指针所指向的物,是这个地点中所存放着具有各类百般意义的数据。


#p#副标题#e#

2、对指针自己值的阐明

下面例子考查指针自己的值(情况为32位的计较机):

void *p = malloc( 100 );

请计较sizeof ( p ) = ?

char str[] = “Hello” ;

char *p = str ;

请计较sizeof ( p ) = ?

void Func ( char str[100])
{
请计较 sizeof( str ) = ? //留意,此时,str已经退化为一个指针,详情见
//下一篇指针与数组
}

阐明:上面的例子,谜底都是4,因为从上面的接头可以知道,指针自己的值对应着内存中的一个地点,它的size只与呆板的字长有关(即它是由系统的内存模子抉择的),在32位呆板中,这个长度是4个字节。

3、对指针所指向物的阐明

此刻再对指针这个复合范例的第二部门,指针所指向物的意义举办阐明。

上面我们已经获得了指针自己的范例,那么将指针自己的范例去掉 “*”号就可获得指针所指向物的范例,别离如下:

a)、int

所指向物是一个整数。

b)、int*

所指向物是一个指向整数的指针。

c)、int ()[3]

()为空,可以去掉,变为int [3],所指向物是一个拥有三个整数的数组。

d)、int ()()

第一个()为空,可以去掉,变为int (),所指向物是一个函数,这个函数的参数为空,返回值为整数。

#p#副标题#e#

4、附加阐明

别的,关于指针自己巨细的问题,在C++中与C有所差异,这里我也顺带谈一下。

在C++中,对付指向工具成员的指针,它的巨细不必然是4个字节,这主要是因为在引入多重虚拟担任以及虚拟函数的时候,有些附加的信息也需要通过这个指针举办通报,因此指向工具成员的指针会增大,岂论是指向成员数据,照旧成员函数都是如此,详细与编译器的实现有关,你可以编写个很小的C++措施去验证一下。别的,对一个类的静态成员(static member,可以是静态成员变量可能静态成员函数)来说,指向它的指针只是普通的函数指针,而不是一个指向类成员的指针,所以它的巨细不会增加,仍旧是4个字节。

指针运算符&和*

“&和*”,它们是一对相反的操纵,’&’取得一个物的地点(也就是指针自己),’*’获得一个地点里放的物(指针所指向的物)。这个对象可以是值(工具)、函数、数组、类成员(class member)等等。

参照上面的阐明我们可以很好地领略&与*。

利用指针的长处?

#p#分页标题#e#

关于指针的本质和根基的运算符我们接头过了,在这里,我想再笼总地谈一谈利用指针的须要性和长处,为我们此后的利用和对后头篇章的领略做好铺垫。简而言之,指针有以下长处:

1)、利便利用动态分派的数组。

这个表明我放在本系列第六篇中举办讲授。

2)、对付沟通范例(甚至是相似范例)的多个变量举办通用会见。

就是用一个指针变量不绝在多个变量之间指来指去,从而使得很是应用起来很是机动,不外,这招也较量危险,需要小心利用:因为呈现错误的指针是编程中很是隐讳的工作。

3)、变相改变一个函数的值通报特性。

说白了,就是指针的传地点浸染,将一个变量的地点作为参数传给函数,这样函数就可以修改谁人变量了。

4)、节减函数挪用价钱。

我们可以将参数,尤其是大个的参数(譬喻布局,工具等),将他们地点作为参数传给函数,这样可以省去编译器为它们建造副本所带来的空间和时间上的开销。

5)、动态扩展数据布局。

因为指针可以动态地利用malloc/new生成堆上的内存,所以在需要动态扩展数据布局的时候,很是有用;好比对付树、链表、Hash表等,这险些是必不行少的特性。

6)、与今朝计较机的内存模子相对应,可凭据内存地点举办直接存取,这使得C很是适合于一些较底层的应用。

这也是C/C++指针一个强大的利益,我会在后头报告C语言的底层操纵时,较具体地先容这个利益的应用。

7)、遍历数组。

据个例子来说吧,当你需要对字符串数组举办操纵时,想一想,你虽然要用字符串指针在字符串上扫来扫去。

…实在太多了,你可以逐步来增补^_^。

#p#副标题#e#

指针自己的相关问题

1、问题:空指针的界说

曾经看过有的.h文件将NULL界说为0L,为什么?

谜底与阐明:

这是一个关于空指针宏界说的问题。指针在C语言中是常常利用的,有时需要将一个指针置为空指针,譬喻在指针变量初始化的时候。

C语言中的空指针和Pascal可能Lisp语言中的NIL具有沟通的职位。那如何界说空指针呢?下面的语句是正确的:

char *p1 = 0;
int *p2;
if (p != 0)
{
...
}
p2 = 0;

也就是说,在指针变量的初始化、赋值、较量操纵中,0会被编译器领略为要将指针置为空指针。至于空指针的内部暗示是否是0,则随差异的呆板范例而定,不外凡是都是0。可是在别的一些场所下,譬喻函数的参数原型是指针范例,函数挪用时假如将0作为参数传入,编译器则不能将其领略为空指针。此时需要明晰的范例转换,譬喻:

void func (char *p);
func ((char *)0);

一般环境下,0是可以放在代码中和指针关联利用的,可是有些措施员(数量还不少呦!也许就包罗你在内)不喜欢0的直白,认为其不能暗示作为指针的非凡寄义,于是要界说一个宏NULL,来明晰暗示空指针常量。这也是对的,人家C语言尺度就明晰说:“ NULL应该被界说为与实现相关的空指针常量”。可是将NULL界说成什么样的值呢?我想你必然见过好几种界说NULL的要领:

#define NULL 0
#define NULL (char *)0
#define NULL (void *)0

在我们利用的绝大大都计较系统上,譬喻PC,上述界说是可以或许事情的。然而,世界上尚有许多其它种类的计较机,其CPU也不是Intel的。在某些系统上,指针和整数的巨细和内部暗示并纷歧致,甚至差异范例的指针的巨细都纷歧致。为了制止这种可移植性问题,0L是一种最为安详的、最妥帖的界说方法。0L的寄义是: “值为0的整数常量表达式”。这与C语言给出的空指针界说完全一致。因此,发起回收0L作为空指针常量NULL的值。

其实 NULL界说值,和操纵系统的的平台有关, 将一个指针界说为 NULL, 其用意是为了掩护操纵系统,因为通过指针可以会见任何一块地点, 可是,有些数据是不许一般用户会见的,好比操纵系统的焦点数据。 当我们通过一个空(NULL)的指针去方位数据时,系统会提示犯科, 那么系统又是如何知道的呢??

以windows2000系统为例, 该系统划定系统中每个历程的起始地点(0x00000000)开始的某个地点范畴内是存放系统数据的,用户历程无法会见, 所以当用户用空指针(0)会见时,其实会见的就是0x00000000地点的系统数据,由于该地点数据是受系统掩护的,所以系统会提示错误(指针会见犯科)。

#p#分页标题#e#

这也就是说NULL值不必然要界说成0,起始只要界说在系统的掩护范畴的地点空间内,好比界说成(0x00000001, 0x00000002)城市起到沟通的浸染,可是为了思量到移植性,普遍界说为0 。

#p#副标题#e#

2、问题:与指针相关的编程法则&法则阐明

指针既然这么重要,并且容易堕落,那么有没有要领可以很好地淘汰这些指针相关问题的呈现呢?

谜底与阐明:

淘汰堕落的基础是彻底领略指针。

在要领上,遵循必然的编码法则大概是最立竿见影的要领了,下面我来叙述一下与指针相关的编程法则:

1) 未利用的指针初始化为NULL 。

2) 在给指针分派空间前、分派后均应作判定。

3) 指针所指向的内容删除后也要排除指针自己。

要紧记指针是一个复合的数据布局这个本质,所以我们岂论初始化和排除都要同时分身指针自己(上述法则1,3)和指针所指向的内容(上述法则2,3)这两个方面。

遵循这些法则可以有效地淘汰指针堕落,我们来看下面的例子:

void Test(void)
{
    char *str = (char *) malloc(100);
    strcpy(str, “hello”);
    free(str);
    if(str != NULL)
    {
    strcpy(str, “world”);
    printf(str);
    }
}

请问运行Test函数会有什么样的功效?

答:

改动动态内存区的内容,效果难以预料,很是危险。因为free(str);之后,str成为野指针,if(str != NULL)语句不起浸染。

假如我们紧记法则3,在free(str)后增加语句:

str = NULL;

那么,就可以防备这样的错误产生。

 

    关键字:

天才代写-代写联系方式