*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
- *p++移动的byte数
- HNWE T3 *p++移动的byte数
- byte.int类型数的计算
- JAVA byte有无符号数的转换
- p,&p,*p的区别
- p,&p,*p的区别
- p &p *p的区别
- p,&p,*p的区别
- p,*p,&p的区别
- *p++/(*p)++/*(p++)的区别
- p,&p,*p的区别
- *p++,*(p++),(*p)++的区别
- 回调函数中lpbyte的处理,ref byte与byte[]
- vc 计算BYTE型数组的字节数
- byte short int占用的字节数简单解释
- 编程之美--BYTE二进制数中1的个数
- matlab如何计算一幅图像的Byte数
- CSDN-P次方数
- C++中的自定义数据类型(结构体)解析
- Android 滑动效果入门篇(二)—— Gallery
- arm调试的准备内容,注意事项,以及BOOTLOADER和散列表加装的分析
- 单篇 Hibernate应用中Java对象的状态
- ARM寄存器小结
- *p++移动的byte数
- Ajax API介绍,以及html5的新特性,jsonp的用法
- 黑马程序员_java第四天基础总结
- malloc、calloc区别 分配在哪里
- Flex样式-HSlider篇
- 相对定位、绝对定位差别
- OpenERP QWeb模板标签笔记
- jbpm4 泳道
- 2014年新年新的一天