【转自馒头e窝】字符指针的特别之处

来源:互联网 发布:cydia安装软件路径 编辑:程序博客网 时间:2024/05/07 00:50
首先非常感谢馒头e窝,看到这么好的分析,自己也转一下,希望对大家有所帮助,反正自己先看上了哈。。大笑
如果我们对一个非字符的指针进行操作,方法是这样的:

  定义:int a=7; int *p=&a; 或者 int a=7; int *p; p=&a; 或者 int a=7; int *p; *p=a;

  这样定义的原因是因为等号两边的类型必须匹配,int *p=&a; 等号左边定义的是一个指针,指针的内容是地址,所以等号右边也应该是地址,&a就是取空间a的地址,第二种情况 int *p; p=&a; 为什么不是 *p=&a 而是 p=&a; 因为在定义的时候“*”只是说明p是一个指针,而p也是一个变量,不过是储存地址的一种特殊的变量,对于变量使用,我们都是直接使用它的名字,就好象,我们定义个常量 const a=7; 我们要调用它的时候直接使用a就可以了,并不需要带上 const 修饰,这里也一样,用指针变量时并不需要带上“*”,而第三种情况中的“*”和第二种里面是不同的,这里的“*”是取内容符,与之相反的是取地址符“&”,分析一下,第三种情况中,等号左边是*p表示对指针p取内容,它的内容指向内存中的某个已经在开始通过 int *p; 定义好的空间里(比较确切一点的说法是,p在定义的时候,其内容里的地址指向内存中某个未知的空白区域,即未占用,不受保护的内存空间),这个空间里存放的数据类型是整型,所以等号的右边也应该是整型才能匹配,所以是 *p=a; 这里的“*”和定义时候的是不同的,这一点很重要。

  其实上面的都是些题外话,我要说的其实是关于指针的输出的一些问题。我们利用上面定义好的进行输出操作。

  输出指针的内容(即所指向空间的地址):cout<<p<<endl;
  输出指针所指的内容(即指针内容所描述地址空间中的内容):cout<<*p<<endl;

  指针对于字符的处理却有些特殊,和前面的非字符的指针输出处理要分开理解。

  比如,我们定义一个 char a='A'; char *p=&a;  如果我们调用上面非字符指针的输出方式,结果如下:
  方式1 cout<<p<<endl; 结果 A####(#表示乱码,不可识别) 并不是地址
  方式2 cout<<*p<<endl; 结果 A 这和非字符的指针情况一样,输出指针指向的内容
  而且我们直接操作 cout<<&a<<endl; 结果和方式1的结果是完全相同的

  为什么方式1输出的不是地址呢?这里有一个特殊的处理,虽然这里的p的内容确确实实是一个地址,但是cout操作字符指针的话,它遇到地址,就会直接去寻找这个地址所指向的内容,并把它的空间里的机器数按照字符的规则转化成字符输出,直到遇到“\0”这个操作符才停止。所以我们直接输出p的时候,它先输出‘A’然后再继续读取后面的内存空间知道遇到“\0”,显示结果是“A+乱码”。

  你肯定会说,为什么要这样呢,这样多不方便呀,其实这么做是有目的的,而且恰恰就是为了方便才这么设置的。因为这样就可以很容易的处理字符串了,而处理字符串是我们在计算机中用得很多的操作。

  比如我们第一个字符串数组 char a[]="mantou"; a[]在内存中在7个字节,而不是6个,因为在mantou字符串后面还隐藏有一个“\0”,这时我们用 char *p=a; (这里不用&a是因为,a[]是一个数组,数组名a本身就是一个指针常量) 输出操作 cout<<p<<endl; 这里就不会输出地址,而是直接输出整个mantou字符串,很方便哈,如果我们 cout<<*p<<endl; 结果显示的是m,因为p是指向数组的首元素的地址的,就是指向这里的储存m的空间的地址,所以取p的内容(*p),只能输出一个m哦。

  虽然通常情况下我们是不需要了解我们的数据地址的,但我也顺便说说,怎么得到字符指针的地址,也可以方便大家对内存地址的分配再做更深入的研究。

  char a='A';  如果这里直接输出 cout<<&a<<endl; 当然是不能输出地址的,原理上面已经说过了,cout遇到字符型地址就会转换成字符输出。我们可以用指针p先取得a的地址(char *p=&a;),但是这样用 cout<<p<<endl; 也并不能得到地址呀,做个小技巧,首先我们知道p中的内容本身就是地址,但是因为它是字符串,我们又不能直接输出它,所以呀,我们可以把指针里的内容(记载的是一个地址数据)强制转化成整型再输出 cout<<(int)p<<endl; 呵呵,这样就得到了这个指针里的内容——十进制型的地址,而我们知道,地址是用十六进制表示的,形式是 0x######## 0x后面加8位十六进制数,我们把我们先得到的十进制地址按照地址的表示形式用流操作转化成十六进制就可以了。代码如下:

cout<<"0x"<<setfill('0')<<setw(8)<<setiosflags(ios::uppercase)<<hex<<(int)p<<dec<<setfill(' ')<<endl;  //流控制实现十六进制地址输出
注意不要忘了 #include<iomanip.h> 这个头文件哦
posted on 2005-10-06 01:39 馒头 阅读(2358) 评论(8)  编辑 收藏 引用 所属分类: 1.『C路艰难』

FeedBack:
# re: 字符指针的特别之处
2005-10-06 10:25 | 馒头
对了,还忘了说一点,你可能会发现,用cout<<&p<<endl;也可以输出地址,但是要注意的是任何变量都是占有储存空间的,指针也是,所以这个输出的地址不是指针里的内容,即不是指针所指向空间的地址,而是指针变量空间本身的地址。  回复  更多评论
  
# cout << (void*)p就行了
2005-10-20 23:58 | 呵呵
iso标准规定了stl的行为,对能隐式转化到const char*的指针cout << *中的operator <<都调用 
basic_ostream& operator<<(basic_ostream&, const char*); 
而其他cout << *形式中能隐式转换到const void*的指针都调用 
basic_ostream& basic_ostream::operator<<(const void*); 
  回复  更多评论
  
# re: 字符指针的特别之处
2010-01-09 14:55 | yyc
very good!  回复  更多评论
  
# re: 字符指针的特别之处

原创粉丝点击