*p++移动的byte数

来源:互联网 发布:mysql导入中文数据乱码 编辑:程序博客网 时间:2024/06/10 04:23

不同数据类型的变量,占用的字节数不同,系统把变量占据存储单元的第一个字节的地址作为该变量的地址

⑴ 间接访问运算

用变量名对其所对应的存储单元的内容进行读写称为直接访问,而通过存储单元的地址对其内容进行读写的则称为间接访问。尽管指针变量中保存的是存储单元的地址,而引入指针的目的主要是为了更方便快捷地访问存储单元的内容。间接访问是在引用的指针变量前面加一个“*”号,用来表示指针所指向的存储单元的值或内容。

需要说明的是:在定义指针变量和在引用时“*”的含义是不同的。【int a=5, *p】中的“*”表示所定义的p是一个指针变量,而在语句printf("%d", *p)中的*p则是间接访问,表示指针变量p所指向的存储单元的内容。由于指针的间接访问是访问存储单元的内容,所以语句*p=&a在编译时也将出现警告错误。

⑵ 指针变量加或减一个整型量,从而得到另一个地址,当然自增自减运算也是合法的。例如当指针变量p指向一个一维数组的首地址,则p+n表示的是下标为n的元素地址。指针变量乘除一个整型量无意义,C语言也不允许此类语句出现。

⑶ 由于指针变量中的地址也是一数值,所以指针变量间也可以进行关系运算。

⑷ 两个类型相同的指针变量可以相减,例如指向同一数组的指针变量相减可以得到两个指针间元素的个数。相加或相乘则无意义。

由于++与*优先级相同,且均为自右至左结合,所以当用间接访问形式使得所指变量自加或自减时,应使用括号。例如:指针变量p已指向变量a,用间接访问形式使得变量a自加1,应写为(*p)++,即等价于a++,但不能写成*p++,*p++是后面要介绍的一种指针运算,所以必须要分开。

由于数组占据一块连续的存储单元,且数组中的各元素的相对位置总是固定的,所以对数组元素的引用除了使用下标外,还可以使用指针运算来实现。

由于C语言中的一维数组名代表数组的首地址,即数组的第一个元素所在存储单元的地址,所以&a[0]与a是等价的,p=&a[0]也可写为p=a。

按照C语言的规定,当指针变量p指向数组中的某一元素时,p+1则指向下一个元素,p+n指向后面第n个元素;同样,p-1指向前一个元素,而p-n则指向前面第n个元素。当指针移动1,系统内部移动的字节数,取决于指针变量p的基类型。若为字符型则指针移动1个字节,若为整型,则指针移动两个字节,依此类推。

当p指向数组a的首地址时,表示数组元素a[i]有四种形式:a[i]    * (a+i)    *(p+i)     p[i]

需要说明的是:指针变量与数组名相比,可以进行自加自减或赋值运算。例如p++或p=p+n,它们分别表示指针变量p指向下一个元素和指向后面第n个元素。而数组名一旦定义,则所代表的地址是不能改变的。虽然*(a+i)也能访问数组中每个元素,但它是通过i的变化来实现的。

由于a[i]可以看作是一维数组名,所以它代表该行的首地址,因此,二维数组a中的任一元素的地址既可以通过&a[i][j]求得,也可以通过a[i]+j求得,即&a[i][j]与a[i]+j等价在一维数组的讨论中,a[i]与*(a+i)等价。因此,若将a[i]+j中的a[i]用*(a+i)代换,则二维数组元素的地址可用*(a+i)+j表示,相应的数组元素表示为*(*(a+i)+j)

值得注意的是:若地址表示法*(a+i)+j中的i,j均为0,则该表达式简化为*a,表示a[0][0]的地址。虽然在C语言中a和*a所代表的物理地址值都是相同的,都是二维数组第一个元素的地址;但是从逻辑上来分析,*a表示元素a[0][0]的地址,而a表示a[0]的地址(在这里a[0]为二维数组中的第一行的一维数组),二者的含义是不同的。*a+1表示元素a[0][1]的地址,或称为列地址,即加1只移动一个元素;而a+1则表示一维数组a[1]的地址,或称为行地址,即加1则移动一行元素。作为基类型为简单类型的指针变量只能指向具体元素的地址(列地址),而不能指向二维数组的行地址

由于C语言中的二维数组元素是以行优先连续存储的,且在内存中元素的存储仍然是线性的,因此可以把二维数组作为一维数组来处理。若一个指针变量p已指向二维数组的第一个元素,那么 i行j列元素的地址可表示为p+i*n+j,而元素的值为*(p+i*n+j),也可以使用p++这样的语句逐一访问二维数组的元素。

为了便于访问二维数组,C语言中还专门设置了指向由n个元素组成的一维数组的指针。定义格式为:

类型 (*指针名)[常量表达式]。 例如 :int  (*p)[4],a[3][4];

由于括号的存在,*首先与p结合,说明p是一个指针变量再与[]结合,说明它指向包含4个整型元素的一维数组。在这里不能省略“()”,因为省略括号后则变成*p[],由于“[]”的优先组高于“*”,所以定义的不再是指向数组的指针变量,而是指针数组

类型 (*指针名)[常量表达式]这种指针变量只能指向一维数组。p+1指向的是下一个一维数组。即指针移动的不是一个元素,而是一行元素。因此,这种类型的指针变量和二维数组名的作用是相同的。若有p=a,则i行j列的元素地址为*(p+i)+j,即a[i][j]与*(*(p+i)+j)等效,表示形式与数组名表示法相同。

在C语言中字符串是存储在字符数组中的字符数组与指针的关系与一维数组与指针的关系基本相同,只是数组与指针均为字符型。当定义一个字符型的指针变量并把它指向一字符数组时,就可以通过指针变量来处理字符串了。

除此之外,字符指针变量还可以指向字符串常量,这是其它类型的指针所不具备的。例如:

char *string="I love my Motherland!";

char *string;

string="I love my Motherland!"

C语言对字符串常量是按字符数组处理的,在内存开辟了一个字符数组用来存放字符串常量。由于指针变量只能保存地址,所以赋给字符指针变量的不是字符串自身,而是字符串的首地址

例7.12  用字符指针实现字符串的复制。

main()

{

char *a="I love my Motherland !",b[40], *p1, *p2;

p1=a;

p2=b;

printf("%s",p1);

while(*p1)

*p2++=*p1++;

*p2='/0';

printf("%s",b);

}

在例7.12中使用的是字符指针,虽然源字符串可以用指针变量定义,但目标字符串必须用字符数组来定义。因为指针变量只能定义一个保存字符串首地址的指针,而没有保存字符的空间。如:

main()

{

char *a="I love my Motherland !", *b, *p1, *p2;

p1=a;

p2=b;

printf("%s",p1);

while(*p1)

*p2++=*p1++;

*p2='/0';

printf("%s",b);

}是错误的,有可能造成系统崩溃。

当然该程序还可以写得更简洁些:

main()

{

char *a="I love my Motherland !",b[40], *p1, *p2;

p1=a;

p2=b;

printf("%s",p1);

while(*p2++=*p1++);

printf("%s",b);

}

虽然字符数组和字符指针变量都能实现对字符串的存储和运算,但二者有本质的区别。

⑴ 字符数组只能在初始化时赋初值,而不能在语句中赋值。例如:

char a[]="I love my Motherland!";

而不能

 char a[30];

 a="I love my Motherland!";

字符指针变量不仅可以初始化,也可以在语句中为其赋值。如:

char *a="I love my Motherland!";

又可以

char *a;

a="I love my Motherland!";

⑵ 字符数组既有确定的首地址,也有存储字符的空间;而字符指针变量只能保存一个字符串的首地址,在未指向具体字符串或字符数组之前,是没有保存字符的空间的。如:

char *t;

scanf("%s",t);

是错误的,有可能造成系统崩溃。

程序实例:

例7.13  将字符数组a中的ASCII码为奇数的字符复制到b数组中去。

main()

{

char a[40]= "I love my Motherland! ",b[40], *p1, *p2;

p1=a;

p2=b;

while (*p1!= '/0')

{

if(*p1%2==1) *p2++= *p1++;

else p1++;

}

*p2='/0';

printf("%s",b);

}

例7.14  将字符数组a中的“*”号删除。

main()

{

char a[40]= "*I* love* my Mothland! **** ",*p1, *p2;

p1=p2=a;

while (*p1!= '/0')

{

if(*p1!= '*') *p2++= *p1++;

else p1++;

}

*p2='/0';

printf("%s",a);

}

用字符指针变量还可以指向一个格式字符串,替代标准输入输出函数中的格式字符串。如:

char * format1="%d%d",*format2="a=%d,b=%d";

int a,b;

scanf(format1,&a,&b);

printf(format2,a,b);

指针数组与前面学过的数组一样,只不过数组的元素是指针类型。指针数组通常用来处理字符串数组或数据结构中的十字链表等

定义指针数组的格式为:数据类型  *数组名[常量表达式]

例如: char *c[10]; 定义了一个指针数组c,它有10个元素,数组元素的数据类型为字符型。也就是指针数组中的元素都是一个字符型指针变量。指针数组与指向数组的指针的定义格式很相近,不可混淆。

例7.15  用指针数组输出字符串数组。

main()

{

char *day_table[]={"Sun","Mon","Tues","Wednes", "Thurs","Fri","Satur"};

int i;

for(i=0;i<7;i++)

printf("%s/n",day_table[i]);

}

程序中使用字符指针直接定义字符串,当然也可以用二维字符数组定义。虽然用字符数组定义需按最长的字符串指定列数,会浪费一些存储空间,但在实际编程中则更加实用。

例7.16  将多个字符串排序后输出。

#include<string.h>

main()

{

char str[][15]={ "Visual Basic","Visual Foxpro","Java","C","Visual C",};

char *name[5], *s;

int i,j,k;

for(i=0;i<5;i++)

name[i]=str[i];

for(i=0;i<4;i++)

{

k=i;

for(j=i+1;j<5;j++)

if(strcmp(name[k],name[j])>0) k=j;

if(k!=i)

{

s=name[i]; name[i]=name[k]; name[k]=s;

}

}

for(i=0;i<5;i++)

printf("/n%s",name[i]);

}

程序中采用了选择排序法对各字符串进行排序。但这种排序不是将字符串交换存储位置,因为每个字符串中有多个字符,交换起来既费时又费力;而是通过修改指针的指向进行排序,实现起来既方便,效率也高。对于字符串比较函数strcmp,是对两个字符串的比较,也就是说首先比较两个字符串的第一个字符,若不相等则结束比较;否则比较两个字符串的第二个字符,直到遇到一个字符串的结束标志。

指向指针的指针

指针数组是通过其下标访问元素的,若使用另一个指针来引用指针数组中的元素,则这个指针就是指向指针的指针。

定义指向指针的指针格式为:类型 **指针变量名

例如:char **p; 由于“*”运算符的结合性是从右至左,**p相当于*(*p),括号内的表示字符型的指针变量,而括号外的“*”则表示该指针变量指向的是字符型指针变量,即为指向字符型指针的指针

例7.17  用指向指针的指针改写例题7.16。

#include<string.h>

main()

{

char str[][15]={ "Visual Basic","Visual Foxpro","Java","C","Visual C",};

char *name[5], *s, **p1, **p2, **p;

int i,j,k;

for(i=0;i<5;i++)

name[i]=str[i];

for(p1=name;p1<name+4;p1++)

{

for(p=p1,p2=p1+1;p2<name+5;p2++)

if(strcmp(*p, *p2)>0) p=p2;

if(p!=p1)

{

s=*p; *p=*p1; *p1=s;

}

}

for(p=name;p<name+5;)

printf("/n%s", *p++);

}

例7.18  用指向指针的指针输出整型数组元素。

main()

{

int a[]={1,2,3,4,5,6,7,8,9,10},i;

int *num[10], **p;

for(i=0;i<10;i++)

num[i]=&a[i];

for(p=num;p<num+10;)

printf("%4d",**p++);

}

该例题只是为了说明指向指针的指针的用法,实际上它与一维数组与指针的关系是一致的。

注意的问题

⑴ 不同类型的指针变量定义形式不同。

如有以下定义:int *p1, (*p2)[10], **p3;

定义中的p1为指针变量;p2则为指向一维数组的指针变量,且一维数组的元素个数为10,在这里不可省略圆括号;p3为指向指针的指针变量。

⑵ 不能引用没有赋值的指针变量,否则可能会造成系统瘫痪。如:

int *p1;

char *p2;

scanf("%d",p1);

scanf("%s",p2);

是错误的。因为只定义了整型和字符型指针变量,没有接收数据的空间。

 数据类型相同且指针类型相同的指针变量可以相互赋值。如有以下定义:

int *p1,(*p2)[10], **p3;

下列赋值语句

p1=p2;

p1=p3;

p3=p1;

p2=p1;

p2=p3;

均是不合法的。

⑷ 除了0之外,常量不能为指针变量赋值,因为变量或数组分配的存储单元是由系统完成的。用0为指针变量赋值,表示指针变量指向空,即不指向任何存储单元。

 

参考文献:http://www.17xie.com/read-272486.html

0 0
原创粉丝点击