• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

[C和指针]第二部分

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
 

25

第四章     指针


指针代表地址,即使用名字来替换地址,它存储的就是一个地址值。名字与内存位置之间的关联并不是硬件所提供的,它是由编译器为我们实现的。这些指针变量名给了我们一种更方便的方法记住地址——硬件仍然通过地址访问内存的位置。
 
每个变量都是包含了一序列内容为01的位,它们可以被解释为整数,也可以被解释为浮点数,这取决于被使用的方式。如果使用的是整型算术指令,这个值就被解释为整数,如果使用的是浮点型指令,它就是个浮点数。
 
 
指针图示:

注意箭头起始于方框内部,因为它代表存储于该变量的值。同样,箭头指向一个位置,而不是存储于该位置的值,这种记法提示跟随箭头执行间接访问操作的结果将是一个左值(即某个变量的地址,如&a,而不是某个变量a的值)。
 
 
    int *a;
    *a =12;
上面的程序是极为危险与错误的。这个声明创建了一个名叫a的指针变量,后面那个赋值语句把12存储在a所指向的内存位置。因为从未对a进行初始化,所以我们没有办法预测12这个值将存储于什么地方。虽然如果变量a是静态的它会被初始化为0,变量为自动的,它根本不会被初始化,但无论是哪种情况,声明一个指向整型的指针都不会“创建”用于存储整型值的内存空间(只有声明一个非指针变量时才会分配存储空间)。该程序在不同的编译器中会产生不同的结果,运气好的话,提示内存错误,运行不好的话,程序表面上会正常结束,而且*a值是正确的,但是这里隐藏了一个极为严重的错误并且一旦出现很难发现:a会覆盖内存中原先随机初始化指向的某个位置的值。所以,在对指针进行间接访问之前,必须非常小心,确保它们已被初始化,如:
    int b, *a;//此时的指针随机指向某个存储空间
    printf("%d\n", a);//随机指向的位置:2147348480
    a = &b;//初始化指针,让它指向某个确定的内存空间
    printf("%d\n", a);//现在指针所指向的位置为:2293576
    *a = 12;//12常量存储到a所指向的某个内存位置
    printf("%d\n", *a);//12
    printf("%d", b);//12
 
NULL指针不指向任何东西。要使指针变量为NULL,你可以给它赋一个零。为了测试一个指针变量是否为NULL,你可将它与零值进行比较。之所以选择零这个值是因为一种约定,就不同机器内部而言,NULL指针实际值可能不是零,在这种情况下,只要使用NULL,编译器将负责零值和内部值之间的翻译转换工作。
 
如果对一个NULL指针进行间接访问会发生什么情况呢?结果会因编译器而异,在有些机器上,它会访问位置为零的地址中的内容,但这是极其错误的;在其他机器上,对NULL指针进行间接访问将引发一个错误,并终止程序,这种情况下程序员就很容易提示发现错误,如XP就是这样的:
    //将字符数组(字符串就是数组)首地址赋给p1
    char *p1="a" ;
    printf("%c",*p1);//a
    //将指针指向内存地址为0的位置
    char *p2=NULL ;
    printf("%c",*p2);//!!出错 
 
  
    int a;
    *&a=12;
上面程序的结果就是将12赋值给变量a&操作符产生变量a的地址,它是一个指针常量,接着,*操作符访问其操作数所表示的地址,在这个表达式中,操作数是a的地址,所以25就存储到a中。这与  a = 12 有区别吗?从结果上讲没有区别,但它涉及到更多的操作。
 
假定a存储于位置100,下面这条语句合法吗?
*100 = 12;
这是错误的,因为字面值100的类型是整型值,而间接访问操作只能作用于指针类型表达式。如果你确实想把12存储于位置100,你必须使用强制类型转换:
*(int *)100 = 12;//100从整型转换为指向整型的指针类型
虽然强转后合法,但通常我们不会这样作,因为我们无法预测编译器会把某个特定的变量放在内存中的什么位置,所以你无法预先知道变量a的地址。这个技巧除非用来访问内存中某个特定的位置,不是某个变量,而是访问硬件本身。
 
 
二级指针(指针的指针):
    int a = 12;
    int *b = &a;
    int**c = &b; 
 

表达式

等效的结果

a

12

b

&a

*b

a , 12

c

&b

*c

b , &a

**c

*b , a, 12

 
 
 
 
 
 
各种指针表达式示例
    char ch = 'a';
    char *cp = &ch;
现在我们有了两个变量,它们初始化如下:

 

表达式

右值

左值

描述

ch

作为右值使用时,粗椭圆表示变量ch的值就是表达式的值(右值为读取);但是,当这个表达式作为左值使用时,它是这个内存的地址而不是该地址所包含的值,此时该位置用粗方框标记(左值为写入,可存储值),表示这个位置就是表达式的结果,另外,它的值并未显示,因为它并不重要,事实上,这个值将被某个新的值所取代。

&ch

非法

作为右值,这个表达式的值是变量ch的地址,这个值同变量cp中所存储的值一样,但这个表达式并没有涉及到cp变量,所以这个结果值并不是因为它而产生的,所以图中椭圆并没有画在cp的箭头周围;作为左值时,当表达式&ch进行求值时,它的结果肯定是存储在计算机的某个地方了,但我们无法知道,所以这个表达式的结果未标识机器内存中的特定位置,所以不是合法左值。

cp

右值就是cp的值,左值就是cp所处的内存位置。

&cp

非法

该表达式为指向指针的指针。这个值存储位置并未清晰定义,所以不是一个合法左值

 

 

 

*cp

现在加入了间接访问符*,所以现在使用实线

*cp+1

非法

图中虚线表示表达式求值时数据的移动过程。这个表达式的最终结果存储位置并未清晰定义,所以不是一个合法左值。

*(cp+1)

指针加法运算的结果是一个右值,因为它存储位置并未清晰定义。如果这里没有间接访问操作*,这个表达式将不是一个合法的左值。然而,间接访问跟随指针访问一个特定的位置,这样*(cp+1)就可以作为左值使用,尽管 cp+1 本身并不是左值。间接操作符是少数几个其结果为左值的操作符之一。

++cp

非法

cp本身先加1,再拷贝,椭圆即为拷贝出来的内容。

cp++

非法

先拷贝cp,再将cp本身加1,椭圆即为拷贝出来的内容。

*++cp

 

*cp++

该文章已有0人参与评论

请发表评论

全部评论

上一篇:
C#发送Email邮件方法总结发布时间:2022-07-14
下一篇:
C++学习笔记15:操作符重载的函数原型列表(推荐)发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap