程序设计基础(7)——指针

指针类型与指针变量

在C中,任何一个类型都伴随着一个指向本类型变量的指针类型。设有类型T,则指向T类型变量的指针类型用

T *

T称为该指针类型的基类型

指针变量简称指针,是一种特殊的变量,它所存储的“值”被解释称为一个变量的地址,也被称为变量的指针。

声名指针变量通过把星号“*”放在变量前实现,即使用如下形式:

*p

其中,p是标识符。

把上述形式放在变量声明中便可以声名指针变量。如

int *iptr1,*iptr2,x,y;

除了声名两个一般的int类型变量x和y以外,还声明了两个指向int类型变量的指针变量iptr1和iptr2,即“int *”类型变量iptr1和iptr2。其中,iptr1和iptr2都是标识符,是被声明的指针类型的变量,确切的说是“指向int类型变量的指针变量”。其中int类型是指针类型“int *”所指的类型

指针类型所指的类型即可以是基本数据了您先给,也可以是构造数据类型,甚至指针类型,还可以是函数。

指针变量的值是内存地址(宏观上讲的是变量的地址)。求取不同类型变量地址的表达方式不同。对于基本类型变量、数组成员、结构体变量、联合体变量等,用求地址运算符“&”获取变量的地址;数组的地址与第一个元素(成员)的地址相同,用数组名字本身表示;函数的地址为函数的入口地址,用函数名字表示。

指针所指的变量

指针变量和指针所指的变量是两个不同的概念。指针变量即指针,它本身存储某个内存地址(某个变量的地址)。指针所指变量为指针变量中所保存的内存地址对应的变量。

例如:

int *iptr;
int i=3,j;
iptr=&i;
变量地址内存
jEAB6
iEAB43
iptrEAB0

EAB4

 系统为int类型指针变量iptr分配的内存单元地址为EAB0,iptr本身值为内存地址EAB4。而地址EAB4对应的是int型变量iptr所指变量为int型变量i,即iptr指向i

       运算符“*”用来访问指针所指变量的内容,称为间接引用运算符。*iptr表示指针变量iptr所指的变量内容。例如

j=*iptr

就是将iptr所指变量中的内容送入变量j,结果j的值为3。、

注意符号“*”的用法:

(1)“*”放在表达式中的指针变量之前,表示“对指针所指变量的访问”,称为间接引用操作符。

(2)“*”放在声明中,表示指针类型,称为指针定义符,用来说明指针变量。

空指针和无效指针

 NUL是C指针类型的一种特殊值,为“空”。若某指针变量的值为NULL,表示该指针变量的值为空,不指向任何变量或函数。NULL属于所有指针类型。判断指针变量iptr的值是否为空可以使用:

iptr!=NULL  或  iptr==NULL 

无效指针是指一个指针变量无效,它既没有指向确定的变量或函数,也不是NULL。产生无效指针的原因很多,例如:

(1)声名指针变量后还没有为其赋值

(2)把整型变量转化为指针

(3)回收为指针所指对象分配的存储空间

(4)指针运算超出数组范围

指针操作

1.求地址“&”

“&”运算符用来求“被操作对象”的地址(即指针)。例如,&x表示变量x在内存中的存储地址(即x的指针),若x的地址为ABD0,则&x的值为ABD0。

2.取内容“*”

“*”与“&”互为逆运算。“*”运算访问地址表达式所指变量。例如,“x=*p”是将指针p所指变量的值送入变量x中;“*p=5”是将5送入指针p所指的变量中。

3.赋值“=”

可以把一个指针值赋值给某个指针变量。所谓指针值是指某变量指针(变量的地址)或函数的指针

指针赋值运算要求赋值号“=”右端的指针值与赋值号“=”左端的指针变量之间类型相容。两个指针值类型相容,是指向它们所指的对象是同一个类型的。

指向指针的指针

如果一个指针变量所指向的变量仍然是一个指针变量,就构成指向指针变量的指针变量,简称指向指针的指针。例如:现有一个指向指针变量的指针变量p,则p的声名如下

类型符  **p

例如:
int **p,*s,v;
p=&s;
s=&v;
v=300;

其中p指向指向s,s指向v

使用s访问v:*s

使用p访问v:**p

这种间接寻址的运算的意义如下:

(1)p是指针变量,它的值是指向“指向int类型的变量”。

(2)*p取p的内容,得到一个指针值,该指针值“指向int类型变量”

(3)**p即“*(*p)”,再取上述“*p”的内容,得到一个int类型的值

指针与数组

指针与数组有着密切的关系。数组名是数组的首地址,也就是a[0]的地址;指针值也是一个地址,如果一个指针p指向数组的首地址,即指向a[0],则p与a表示的是同一个对象。事实上,在C中把指针和数组当做同一个概念对待,数组名是指针,指针也是数组

用指针标识数组

在C中,数组名是指针,指向数组的首元素(下标为0的元素),也就是数组第一个元素的地址。可以把这个指针值送入指针变量中。例如

int a[5];
int *iptr;
iptr=a;   //或者使用&a[0]

其中,iptr,a,&a[0]均表示同一地址。即存放数组第0个元素的地址。

注意:数组名不代表整个数组,而是数组的首地址,即第一个元素额地址。上述的“iptr=a”不是把整个数组a全部送入iptr中,而是把数组a的首地址(即a[0]的地址)送入iptr中

指针运算

1.加+(++)

如果指针指向数组的一个元素,C允许对相应指针值加上一个整数表达式。设指针p指向数组变量a的一个元素,把指针p与一个整数k相加,得到的结果值仍然是一个指针值,该值指向的是“数组a从p原来所指元素开始,想数组尾部移动k个元素后的元素”

例如:
int *p,*q,*r,a[100];
p=&(a[10]);
则
p=p+3;   //此时p指向a[13]
若再有
q=p+4    //此时q指向a[17]

 2.减-(--)

指针的减法运算包括指针值减去一个整数表达式和两个相容的指针值相减

(1)如果指针值指向数组的一个元素,“-”的含义与“+”类似,只不过指针p与一个整数k相减,是指向数组首部移动k个元素

(2)如果两个指针相容,即它们指向的对象是同一个类型,则可以进行相减运算,得到的结果是整数类型的值,为两个指针之间的距离。

注意:指针的加减法有如下的限制

(1)若p指向的不是数组元素,或p+k、p-k超出数组元素a的范围,其行为是未定义的,将产生不可预料的结果

(2)不能针对函数指针或void*类型进行加减运算

(3)不允许两个指针间进行加减运算

(4)不允许不相容的两个指针值加减。事实上只有两个指针指向同一个数组中的元素时,做相减运算才有意义。

3.判等运算和关系运算

C还可以针对相容类型的指针进行判等运算和关系运算,得到的结果是bool类型的true或false。针对指针类型的判等运算和关系运算包括以下几种:

(1)判断两个指针值是否相等或不相等(==或!=)

(2)比较两个指针值的大小(>、<、<=、>=)

例如
px<py    //判断px所指向的存储单元地址是否小于py所指的存储单元地址
px==py   //判断px与py是否指向同一存储单元
px==0    px!=0    px==NULL    px!=NULL  //都是判断px是否为空指针

 一定要注意,参与关系运算的指针值是否是形容类型的,如果p指向一个int类型变量,而q指向一个float类型变量,进行p与q的比较是错误的

应该注意的问题

1.数组名是常量指针

例如:设存在一个数组a[6]
for(p=a;p<a+6;p++)
{
     printf("%d",*p);
}
上述代码是合法的,p为指针变量,可进行不断地加1操作

虽然数组名也是指针,但是对数组名却不能进行这样的操作,因为数组名a为指针常量,对数组名a++是非法的
for(a=p;a<p;a++)
{
  printf("%d",*a);
}

 2.指针变量的当前值

设存在数组int a[10],*iptr;

例如:执行语句“iptr=&(a[2])”被执行后,则iptr[i]、*(iptr+i)访问的是数组元素a[i+2],而不是a[i],他们与a[i+2]、*(a+i+2)等价

使用指针形式访问数组元素,是从指针变量当前所指的位置开始“向前”或者“向后”计算,而不是当初给指针变量赋的初值

3.数组越界

C系统不会检查数组超界

4.指针变量的运算

int a[10],*ptr,v,*q,u;
v=5;
ptr=&(a[v])
a[4]=40;
a[5]=50;
a[6]=60;

(1)ptr++

运算“ptr++”的意义是把ptr的值加1,运算结束后ptr指向a[6]。但是表达式的值是ptr加1之前时的ptr的值,即a[5]的地址,若运行

q=ptr++

则结果q指向a[5],ptr指向a[6];

(2)*(ptr++)和*ptr++

由于运算符“*”和运算符“++”的优先级相同。结合方向是从右向左,因此*(ptr++)就是*ptr++

按照(1)的解释,ptr++的值是a[5]的地址,*(ptr++)是求a[5]的值,为50.该运算相当于a[v++]。若有

u=*(ptr++)

则u的结果是50

(3)(*ptr)++

“*ptr”是求ptr所指变量的值,即a[5]的值为50;“(*ptr)++”是a[5]++,最后a[5]的值为51,而该表达式的值为加1之前的值,仍然是50.若有

u=(*ptr)++

则结果u的值为50,a[5]的值为51

(4)++ptr

与(1)类似,运算“++ptr”的意义是把ptr的值加1,运算结束后ptr指向a[6].该表达式的值是ptr+1之后的ptr的值,即a[6]的地址。若有

q=++ptr

则结果q指向a[6],ptr指向a[6]

(5)*(++ptr)与*++ptr

与(2)类似,由于运算符“*”和运算符“++”的优先级相同。结合方向是从右向左,因此*(++ptr)就是*++ptr。按照(4)的讲述,“++ptr”的值是a[6]的地址,则“*(++ptr)”是求a[6]的值,得60。该运算相当于“a[++v]”.若有

u=*(++ptr)

则结果u的值为60

指针数组

一维指针数组的声明如下:

T * p[n]

其中:

(1)T是类型

(2)p是标识符,是被声明的数组变量

(3)n是数组的大小

该声名的意义应该如下解释:

由于运算符“*”的优先级低于运算符“[]”,所以该声名相当于声名

T  *(p[])

按此格式,p[n]表示p是一个n个元素的数组,数组元素是“T *”类型,即指向T类型变量的指针类型。所以p是n个元素的指针数组,数组元素是指向T类型变量的指针。也就是说,p本身是一个指针常量,指向n个元素的数组,数组的每个元素是指针。

指针与字符串

字符串实质上是常量字符数组,同时还可以使用字符数组变量保存字符串。指针与数组有着密切的关系,数组名是指针,指针也可以指向数组。在C中,除了用字符数组保存字符串以外,还可以使用字符类型指针指向一个字符串,从而使用指针访问它所指的字符串。该字符串既可能是字符数组,也可能是字符串常量。

字符串指针与字符数组之间的关系

1.从字符串角度看:字符串指针与字符数组是不同的

a.字符串指针名字是一个指针类型变量,被分配的指针类型存储空间,它虽然可以指向一个字符串,但是字符串指针变量的存储空间不能保存一个字符串。

b.字符数组是一个数组类型变量,被分配数组类型存储空间,该空可以保存一个字符串

2.从指针角度看:字符串指针名字与字符数组名字也是不同的

a.字符串指针名字是一个指针变量,它可以指向任何字符串。可以把任意字符串首指针赋值给字符串指针,让字符串指针指向相应的字符串,但是绝不是字符串指针变量本身存储了整个字符串。

b.字符数组名字是一个指针常量,它只能指向分配给它的那块内存空间,不能让它指向其他字符串或数组。也不能用一个赋值运算把整个字符串赋值给一个字符数组、

3.从使用角度看:

a.不论是字符串指针还是字符数组,访问整个字符串时都需要十分小心,有些操作是正确的,有些操作是错误的。譬如:

a. char str[20]="I am a teacher"; //正确,初始化数组str
b. char str0[20],str[20]="I am a teacher";
   str0=str;                     //错误。给指针常量赋值,数组不能整体赋值
c. char str[20];
   str="I am a teacher";         //错误,给指针常量赋值,数组不能整体赋值
d. char str[20];
   str[]="I am a teacher"        //错误,给指针常量赋值
                                 //str[]出现在=左端,意义不明
e. char *str
   str="I am a teacher"          //正确,给指针变量赋值,str指向常量字符串
f. char str[20];
   scanf("%s",str);              //正确,输入字符串
g. char * str;
   scanf("%s",str);              //错误,str不指向任何变量,输入字符串无处存放
h. char *str,stro[20];
   str =str0;
   scanf("%s",str);              //正确,输入的字符串数据从str0[0]开始存放
i. char *str,str0[20];
   str=str0+5;
   scanf("%s",str);              //正确,输入的字符串数据从str0[5]开始存放
j. char str[20]="I am a teacher";
   printf("%s",str);             //正确,打印:I am a teacher
k. char *str="I am a teacher";
   printf("%s",str);             //正确,打印:I am a teacher
l.char *str="I am a teacher";
  str=str+5;
  printf("%s",str);               //正确,打印:a teacher
m.int x,y;
  char *str ="x=%d y=%df\n";
  printf(str,x,y);                //正确:相当于printf("x=%d y=%f\n",x,y);

  

b.不论是字符串指针还是字符数组,都可以用相同的方法访问其分量。 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值