C指针典例
发布日期:2021-06-29 14:56:03 浏览次数:2 分类:技术文章

本文共 4043 字,大约阅读时间需要 13 分钟。

C指针典例

2015-03-10 李海沿

一、指针的算术运算

例一、

1、 char a[20];

2、 int *ptr=a;

3、 ptr++;

在上例中,指针ptr的类型是int*,它指向的类型是int,它被初始化为指向整形变量a。接下来的第3句中,指针ptr被加了1,编译器是这样处理的:它把指针ptr的值加上了sizeof(int),在32位程序中,是被加上了4。由于地址是用字节做单位的,故ptr所指向的地址由原来的变量a的地址向高地址方向增加了4个字节。由于char类型的长度是一个字节,所以,原来ptr是指向数组a的第0号单元开始的四个字节,此时指向了数组a中从第4号单元开始的四个字节。

 

例二、

1、 char a[20];

2、 int *ptr=a;

3、 ptr+=5;

在这个例子中,ptr被加上了5,编译器是这样处理的:将指针ptr的值加上5乘sizeof(int),在32位程序中就是加上了5乘4=20。由于地址的单位是字节,故现在的ptr所指向的地址比起加5后的ptr所指向的地址来说,向高地址方向移动了20个字节。

在这个例子中,没加5前的ptr指向数组a的第0号单元开始的四个字节,加5后,ptr已经指向了数组a的合法范围之外了。

虽然这种情况在应用上会出问题,但在语法上却是可以的。这也体现出了指针的灵活性。

如果上例中,ptr是被减去5,那么处理过程大同小异,只不过ptr的值是被减去5乘sizeof(int),新的ptr指向的地址将比原来的ptr所指向的地址向低地址方向移动了20个字节。

 

 

总结一下,一个指针ptrold加上一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold的值增加了n乘sizeof(ptrold所指向的类型)个字节。

就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向高地址方向移动了n乘sizeof(ptrold所指向的类型)个字节。

一个指针ptrold减去一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold的值减少了n乘sizeof(ptrold所指向的类型)个字节,就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向低地址方向移动了n乘sizeof(ptrold所指向的类型)个字节。

 

二、指针表达式

例一、

int array[10]={0,1,2,3,4,5,6,7,8,9},value;

value=array[0];//也可写成:value=*array;

value=array[3];//也可写成:value=*(array+3);

value=array[4];//也可写成:value=*(array+4);

上例中,一般而言数组名array代表数组本身,类型是int [10],但如果把array看做指针的话,它指向数组的第0个单元,类型

是int *,所指向的类型是数组单元的类型即int。因此*array等于0就一点也不奇怪了。同理,array+3是一个指向数组第3个

单元的指针,所以*(array+3)等于3。其它依此类推。

 

例二、

char *str[3]={

"Hello,this is a sample!",

"Hi,good morning.",

"Hello world"

};

char s[80];

strcpy(s,str[0]);//也可写成strcpy(s,*str);

strcpy(s,str[1]);//也可写成strcpy(s,*(str+1));

strcpy(s,str[2]);//也可写成strcpy(s,*(str+2));

上例中,str是一个三单元的数组,该数组的每个单元都是一个指针,这些指针各指向一个字符串。把指针数组名str当作一个指针的话,它指向数组的第0号单元,它的类型是char**,它指向的类型是char *。

*str也是一个指针,它的类型是char*,它所指向的类型是char,它指向的地址是字符串"Hello,this is a sample!"的第一个字

符的地址,即'H'的地址。 str+1也是一个指针,它指向数组的第1号单元,它的类型是char**,它指向的类型是char *。

*(str+1)也是一个指针,它的类型是char*,它所指向的类型是char,它指向"Hi,good morning."的第一个字符'H',等等。

 

三、指针与结构类型

例一:

struct MyStruct{

int a;

int b;

int c;

}

MyStruct ss={20,30,40};//声明了结构对象ss,并把ss的三个成员初始化为20,30和40。

MyStruct *ptr=&ss;//声明了一个指向结构对象ss的指针。它的类型是

MyStruct*,它指向的类型是MyStruct。

int *pstr=(int*)&ss;//声明了一个指向结构对象ss的指针。但是它的类型和它指向的类型和ptr是不同的。

请问怎样通过指针ptr来访问ss的三个成员变量?

答案:

ptr->a;

ptr->b;

ptr->c;

又请问怎样通过指针pstr来访问ss的三个成员变量?

答案:

*pstr;//访问了ss的成员a。

*(pstr+1);//访问了ss的成员b。

*(pstr+2)//访问了ss的成员c。

 

四、指针与函数的关系

可以把一个指针声明成为一个指向函数的指针。

int fun1(char*,int);

int (*pfun1)(char*,int);

pfun1=fun1;

int a=(*pfun1)("abcdefg",7);//通过函数指针调用函数。

可以把指针作为函数的形参。在函数调用语句中,可以用指针表达式来作为实参。

 

五、指针类型转换

如果有一个指针p,我们需要把它的类型和所指向的类型改为TYEP*和TYPE,那么语法格式是:

(TYPE*)p;

这样强制类型转换的结果是一个新指针,该新指针的类型是TYPE*,它指向的类型是TYPE,它指向的地址就是原指针指向的地址。而原来的指针p的一切属性都没有被修改。一个函数如果使用了指针作为形参,那么在函数调用语句的实参和形参的结合过程中,也会发生指针类型的转换。

int a=123,b;

int *ptr=&a; //此时ptr指针的内容是a的地址,此处有点绕

char *str;        

b=(int)ptr;        //把指针ptr的值当作一个整数取出来。

str=(char*)b;        //把这个整数的值当作一个地址赋给指针str。

好了,现在我们已经知道了,可以把指针的值当作一个整数取出来,也可以把一个整数值当作地址赋给一个指针。

 

六、指针的安全问题

例一、

char s='a';

int *ptr;            

ptr=(int*)&s;

//ptr指向的是S的地址,将原先的1个字节(有效地址)拓展为4个字节(其他三个字节为非法地址)

*ptr=1298;        

//1298将s指向的地址的后面三个非法地址给重新赋值,超出了允许的地址,重则引起系统奔溃

 

指针ptr是一个int*类型的指针,它指向的类型是int。它指向的地址就是s的首地址。在32位程序中,s占一个字节,int类型占四个字节。最后一条语句不但改变了s所占的一个字节,还把和s相临的高地址方向的三个字节也改变了。这三个字节是干什么的?只有编译程序知道,而写程序的人是不太可能知道的。也许这三个字节里存储了非常重要的数据,也许这三个字节里正好是程序的一条代码,而由于你对指针的马虎应用,这三个字节的值被改变了!这会造成崩溃性的错误。

 

 

例二、

1、 char a;

2、 int *ptr=&a; //ptr指向a的地址,有效地址长度为1个字节

3、 ptr++;            //此处指针自加后,指向a的地址的下一个字节,为非法地址

4、 *ptr=115;        //此处对非法地址进行了非法操作

 

该例子完全可以通过编译,并能执行。但是看到没有?第3句对指针ptr进行自加1运算后,ptr指向了和整形变量a相邻的高地址方向的一块存储区。这块存储区里是什么?我们不知道。有可能它是一个非常重要的数据,甚至可能是一条代码。而第4句竟然往往这片存储区里写入一个数据!这是严重的错误。所以在使用指针时,程序员心里必须非常清楚:我的指针究竟指向了哪里。

    在用指针访问数组的时候,也要注意不要超出数组的低端和高端界限,否则也会造成类似的错误。

 

注意:

在指针的强制类型转换:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的类型)大于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是安全的。如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的

 

 

看看以下代码,想想运行结果:

#include 
int *p;pp(int a,int *b);main(){ int a=1,b=2,c=3; p=&b; printf("(1) %d %d %d \n",a,b,*p); pp(a+c,&b); printf("(3) %d %d %d \n",a,b,*p);}pp(int a,int *b){ int c=4; *p=*b+c; a=*p-c; printf("(2) %d %d %d \n",a,*b,*p);}

 

 

转载地址:https://ciellee.blog.csdn.net/article/details/82599467 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:20150222 IO端口映射和IO内存映射(详解S3C24XX_GPIO驱动)
下一篇:XHR详细讨论

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年04月12日 00时12分09秒