当前位置:编程学习 > C/C++ >>

关于C++指针和引用

我有两个函数如下:

template<class T>
void show(T& data)
{
 cout << data << endl;
}

char* getName()
{
 return "bbb";
}

main函数中的代码如下:

第一种写法:

char *name = "aaa";

show(name);

第二种写法如下:

show(getName());

请问一下,为什么第一种写易做图确,第二种写法无法通过编译,谢谢。

追问:可是我的getName函数返回值写的是char*啊?
答案:函数参数的引用必须是 "变量名称"
比如函数: void Func(int& _iNumber) 
你可以这样调用:  int iA=100;  Func(iA);
但是你不能这样用: Func(100);


char *name="aaaa";  首先name是个指针变量,本身在内存中有4个字节,而其值是一个指针,指向值为“aaaa"的内存段 。 函数 show(name) 传入的值其实是name的地址,就是&name的值
而getName()返回的值 是”bbb"的地址并不是 char 指针变量的地址,所以编译错误。


在编译之后, 函数Func 运行时,寄存器AX取值是参数的地址,不是参数值本身。
用Func(iA)  寄存器AX是  &iA 并非100。


这样调用在编译的时候是正确的:
show((char*&)"ggg");  但是行结果不正确。


其实就一句话,你的函数show 要求参数是只想一个字符串的指针的指针,并非字符串的指针。


E:\c\C++\sosowenwen\soso.cpp(19) : error C2664: 'void __cdecl show(char *& )' : cannot convert parameter 1 from 'char *' to 'char *& '
        A reference that is not to 'const' cannot be bound to a non-lvalue

你记住规则就是了。
例外给你转了一篇关于char*的文章,建议你看看。
 先看以下代码:
  char *p;
  p="abc";
  你认为是对的吗?
  答案:语法上是对的,但不提倡这种写法。
  误区1:没有给p分配内存空间就赋值,怎么会是对的呢?
  正解:不少人第一眼将这里的p="abc"看成了*p="abc",然后就做出了以上的论断。这是比较笨笨的错误咯:)
  看清楚就好啦,其实赋给p的是"abc"的地址。再说,*p="abc"也不对呀,字符串可不能这么赋值。
  误区2:这"abcd"哪来的地址,怎么能直接赋给p呢?
  正解:先自己试试吧。在2K/XP + VC下运行这段代码,是不会出错的,说明这段代码并无问题。晕吧?猜想的话呢,就是"abcd"不知道被放在了什么地方,然后弄来了一个地址,给了p。
  这到底是怎么回事呢?
  要知道,这两个语句和char *p="abc"是完全一样的,所以其中的道理也一样。
  char *p="abc"曾经迷惑了不少人呀。问问你:p到底是什么类型的?char *?错,是const char *!
  也就是说,它所指向的内容是不可改变的。不过要补充的是,a的指向是可以改变的。
  所以为了不再引起误会,char *p="abc这种写法是不提倡的。
  既然char *p="abcd"被建议写成const char *p="abcd",那么char *p; p="abcd";也应该写成const char *p; p="abcd";
  讲来讲去,最后来得看看汇编代码。看完就明白是怎么回事了。(我才发现汇编代码原来这么爽看!VC下,没开编译器优化):
  我们重点先看const char *p="abc"和char p[]="abc"有什么不同(都放在main()中声明):
  PHP源码:
  void main()
  {
   const char *p="abc";
  }
  3: const char *p="abc";
  00401028 mov dword ptr [ebp-4],offset string "abc" (0041f01c)
  void main()
  {
   char p[]="abc";
  }
  3: char p[]="abc";
  00401028 mov eax,[string "abc" (0041f01c)]
  0040102D mov dword ptr [ebp-4],eax
  看出差别了吗?上一段ASM用offset取"abc"的地址,然后赋给[ebp-4],也就是p(下同)。
  而下一段ASM却转了一个弯,先把"abc"的地址转到寄存器eax,然后再转赋给p。
  有疑问了:为什么不和上面的一样,直接用offset?VC是很聪明的(废话,M$的东西呀),不用offset,恐怕就是用不了了。
  offset是一条伪指令,在编译的时候就已经把偏移量算好了。offset是无法执行间接寻址的计算的。
  说明了什么?
  const char *p="abc"中的"abc",在编译期间就已经处理好,要了一块内存,存起来了!在把地址赋给p的时候,就可以直接用offset计算。
  而char p[]="abc"中的"abc",是在运行期间动态分配内存给"abc",然后再算出地址,赋给p。hehe,这同时也说明了数组和指针的等价性。
  我们再做一次实验,这一次我们把char p[]="abc"放在main()外,并在main()内用一个指针再指向p看看。
  PHP源码:
  char p[]="abc";
  void main()
  {
   char *t=p;
  }
  5: char *t=p;
  00401028 mov dword ptr [ebp-4],offset p (00421adc)
  这回p[]的声明放在main()外,变成了全局变量。结果main()内的t取p的指针的时候,直接用offset可以计算出来。
  据小石头所说,字面值,const,static,inline,全局变量都是放在静态数据区的。(但我感觉似乎不是如此,只是全局变量和字符串在编译时就处理好放在一起)
  不难发现,p[]被声明成全局变量后,就可以直接用offset计算地址,说明静态数据区是编译时就已经处理好的。
  再对照const char *p="abc"的ASM,我们马上想到:"abc"就是被C/C++存在静态数据区中的!它的地址就是"abc"在静态数据区的地址!
  弄清了这个,有些问题也就可以想得通了。下面这种用法,看来不能说是错误的了,因为"abc"是在静态数据区的,生存期可以说是整个程序:
  PHP源码:
  #include "stdio.h"
  const char *fun()
  {
   const char *p="abc";
   return p;
  }
  void main()
  {
   const char *t=fun();
   printf ("%s",t);
  }
  看ASM:
  PHP源码:
  5: const char *p="abc";
  00401038 mov dword ptr [ebp-4],offset string "%d" (0042001c)
  一样也是使用offset计算地址。
  C/C++给字符串的待遇真是太好了。为了一个字符串,几乎可以打破所有的指针规则。晕~~~~(完)
  附:第一次写这么长的文章,写得挺晕的。本来我的C/C++也不是很纯熟的,ASM也是一知半解,今天在CSDN上为这个问题郁闷了半天,和几个人讨论了一下,最后就写了这么一篇文章。希望大家赏脸看看~~~有错一定要指正啊!最后特别感谢小石头(想飞的菜鸟,骄傲的石头,菜菜,都是他咯),还有小阿哥(就是Kingzeus咯)的帮忙~~~~~~谢谢咯~~~~~~
  __________________
  小菜虎 -> 菜菜的老虎
  骄傲的石头回复:
  堆几盘积木,心情好些了,所以再重新写一遍。
  关于字符串的这个问题,我一直在心里困惑着。所以呢,昨天就看了一下。
  以前回答别人的时候,总是很简单的回答,字符串就是const char *指针,指向它的入口地址。现在想来真是惭愧,虽然这个事实好象已经为大家所接受,甚至没有人探讨过这个问题!所以我相信我的发现对大家大多数是有好处的。
  首先请看以下代码
  PHP源码:
  #include <iostream>
  #include <iomanip>
  using namespace std;
  int main()
  {
   const char *p = 0;
   char *p2 = p;
   return 0;
  }
  
  以上代码有问题吗? 如果你说没有,请你试一下。很明显,这是有问题的。const是为了保证不变性,而你把他变成non const,肯定有错误或者警告,要么就要用const_cast转换。
  所以上面的代码不能通过编译。
  那么这就很明显的在lee的post里出现了问题,当然我以前也一直是这么认为,甚至很多人都是这么认为。难道这是编译器对字符串的特殊处理吗? 还是其他的原因?
  于是我想看看究竟。就动用了RTTI,我飞快的键入了以下代码。
  PHP源码:
  #include <iostream>
  #include <iomanip>
  using namespace std;
  int main()
  {
   cout << typeid("abc").name() << endl;
   return 0;
  }
  
  你说结果是什么?
  是char [4]!而不是const char *;
  好,这个结果解决了我心中的疑点,原来是这样!这可以很简单的解释char *p = "abc"这个问题。 数组是一个char *const 指针,当然可以赋给char *指针而不会影响其常量性。所以这是完全正确的赋值。
  其实这想起来也很平常,指针是没有分配空间的地址而已,而数组是一种容器,占用连续的储存空间。想想字符串就该知道它是一个数组!而不是指针!真正意义上的指针只能是地址,而它在分配了连续的空间后可以作为数组来使用,这是由于他们的共性而决定的。
  哈哈!心情愉快,所以也接着看了下lee上面所做的探讨。字符串是放在静态储存区没错,毫无疑问。至于位置~ 偶不想多说,lee在上面分析了很多。所以我只对它进行了一下简单的测试。
  我手头上只有dev c++ 和 vc70编译器,所以就只用他们进行了测试。(打开了全部优化)
  PHP源码:
  #include <iostream>
  #include <iomanip>
  using namespace std;
  int main()
  {
   char *p = "abc"
   char *p2 = "abc";
   p[1] = 'k';
   p2[1] = 'j'
   cout << p1 << endl;
   cout << p2 << endl;
   return 0;
  }
  
  结果呢?在dev c++下报错, 原因我想可能是因为在dev c++在对静态储存区进行了保护。而vc70下,通过,并且两个输出是不同的。所以偶去看vc70产生的msil码,原来vc70每次处理字符串都在静态区分配了空间,而且这两个"abc"是连续分配的!这里就没有出现Solmyr说的那种情况。我想一般比较好的编译器也应该这么说。至于vc60,偶没有测试,但是可能Solmyr说的情况会出现吧。但这样是不好的,相信这样会出现很多微妙的情况。
  所以

上一个:c++是什么意思啊
下一个:C++新手指针习题

CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,