【问题标题】:Is this method evaluating a null string?此方法是否评估空字符串?
【发布时间】:2015-02-22 02:38:36
【问题描述】:

我是 C++ 新手,所以如果这是一个愚蠢的问题,请多多包涵。

下面的方法似乎创建了一个名为reversePhrase但没有初始值的字符串,然后使用它phrase.evalPalindrome(reversePhrase)

void testForPalindrome(string origPhrase)
{
   string reversePhrase;
   bool isPalindrome;
   Palindrome phrase(origPhrase);


   if (phrase.evalPalindrome(reversePhrase))
   {
      cout << "This phrase IS a palindrome!" << endl; 
   }
   else
   {
      cout << "This phrase is NOT a palindrome." << endl; 
   }
   cout << "Original phrase: " << origPhrase << endl;
   cout << "Reverse phrase: " << reversePhrase << endl << endl;
}

在 java 中,这将创建一个空指针异常。但是我分析了正在调用的方法,它看起来像是接受字符串的地址。

bool Palindrome::evalPalindrome (string& reversePhrase)
{
   // code
}

但我不明白这是如何工作的。最初的string reversePhrase; 是否只是将内存分配给reversePhrase?如果是,那么调用函数如何能够打印出从另一个函数修改的reversePhrase(代码未显示,但它是从另一个函数修改的)。

用这种方式编写代码似乎很难阅读。

【问题讨论】:

  • String reversePhase = new String(); 在 Java 中等于 string *reversePhase = new string(); 在 C++ 中。在 Java 中,reversePhase 在这种情况下是指针,所以如果你不给它分配任何东西,你会得到一个异常。

标签: c++ pointers syntax


【解决方案1】:

在java中这会产生一个空指针异常。

这是因为 Java 是一种不同的语言,具有不同的对象创建语法。

在 C++ 中,只要您编写了 string reversePhrase,该对象就已经完全形成并可以使用了。


但我分析了正在调用的方法,它看起来像是接受字符串的地址。

不,它接受对字符串的引用!这就是为什么调用范围以后可以看到修改后的字符串!

【讨论】:

  • 在课堂上我们被告知&amp; 是'addressOf'操作符。所以我只是假设这就是正在传递的内容。
  • &amp; 上的点!这让我感到困惑的原因是因为在 java 中该代码永远不会编译(我知道它们是不同的语言)。
  • @inquisitor:是的,它也不会在 FORTRAN 中编译。既然您知道它们是不同的语言,那么您也已经知道在使用 C++ 时应该停止以 Java 术语思考!
  • 还不错哈哈。感谢您在这里的洞察力。非常感谢
【解决方案2】:

string&amp; reversePhrase 没有声明 evalPalindrome 来获取字符串的地址。它声明了一个函数来获取一个字符串的reference。 (用string* 声明它意味着字符串的地址,也就是指向字符串的指针。)

在 C++ 中,当您初始化不带参数的字符串时:

string reversePhrase;

它创建一个空字符串,所以reversePhrase 等于""。因此它不是空字符串,只是一个空字符串,您可以通过引用 evalPalindrome 函数安全地传递它,然后该函数将能够修改传递给它的原始字符串对象。

【讨论】:

  • 我明白了。那么evalPalindrome(string&amp; reversePhrase) 方法只是简单地修改了它传递的引用,这就是为什么它可以在调用方法的末尾使用?
  • @inquisitor 没错,通过非常量引用传递允许函数修改原始对象。
  • 现在开始变得有意义了。您是否同意这会使代码更难阅读?这一定是为什么我看到const 在 c++ 中被如此频繁地使用
  • 不,它专门使它更容易理解。将对象传递给函数的每种方式(通过值、(非)const 引用或(非)const 指针)都传达了不同的语义含义,this answer here 很好地总结了它们。
  • @inquisitor:是的,是的。
【解决方案3】:

您创建的不是指针,而是字符串类型的对象。它永远不会被分配,所以它应该只是一个空白字符串“”。获取到它的地址会很好,因为它是一个有效的对象。

我不确定该功能如何发挥作用。

【讨论】:

  • 我想我对代码感到困惑。 phrase.evalPalindrome(reversePhrase) 是否赋予 reversePhrase 其价值? reversePhrase 什么时候收到过值?
  • 它没有。打开你的 C++ 书籍到关于references的章节!
  • 我知道什么是引用以及它们是如何工作的?他有一个将字符串反转为空字符串的参考,不是吗?我很困惑。
  • 不。结果进入“空白字符串”。输入来自该函数所属的Palindrome 对象。
【解决方案4】:

这里发生的就是所谓的按引用传递。通常,当您在 C++ 中传递变量时,会生成它的副本。这就是为什么当您运行以下命令时,您会得到“A”、“B”、“A”。

int main(){
    string s = "A";
    cout << s << endl;
    cngLetter(s);
    cout << s << endl;
}

void cngLetter(string s){
    s = "B";
    cout << s << endl;
}

如果你通过引用传递,那么它将在主线程上更新它。以下将打印“A”、“B”、“B”

int main(){
    string s = "A";
    cout << s << endl;
    cngLetter(s);
    cout << s << endl;
}

void cngLetter(string& s){
    s = "B";
    cout << s << endl;
}

请注意,只添加了一个字符,&amp;,它导致通过引用传递,即不是副本,而是内存地址。我不需要在这篇文章中输入很多内容,您可以阅读它here

现在strings 不是非托管内存,所以如果你一开始不分配它,那么你会得到""、"B"、"B"

int main(){
    string s;
    cout << s << endl;
    cngLetter(s);
    cout << s << endl;
}

void cngLetter(string s){
    s = "B";
    cout << s << endl;
}

基本上,没有给出初始值的字符串只是一个空字符串。

【讨论】:

  • “线程”在这里不是正确的词。引用和内存地址不是一回事。 “非托管”也有其他含义。
  • 当然,如果“理解重点”是指“教授错误的术语,传播错误信息并混淆所有人”。 :-)
【解决方案5】:

在此上下文中的“&”运算符是“*”的语法糖果。在 evalPalindrome 方法中,虽然 reversePhrase 作为指针传入,但它总是被取消引用。这使得不取消引用指针的常见错误成为不可能。你是对的,它可能会使代码混淆,因为传入的值可以被修改,就像它作为指针传入一样,除了调用函数没有指示它作为指针传入除非您专门查看方法签名。

【讨论】:

  • &amp; 这里不是运算符,也不是“'*' 的语法糖果”,尽管我很欣赏您尝试进行的比较。但最终,您正在固定关于潜在实施的细节,并在此过程中传播一些危险的错误信息。
  • &amp; 对象不占用额外内存,这与 * 对象不同,它由(通常)4 个字节组成。 &amp; 只是分配给它的对象的另一个名称。有点像我可以称你为 Randy 或 Kamrady,你俩都是。
  • @David:实际上,未指定引用是否占用内存([C++11: 8.3.2/4]),但这是一个抽象泄漏,因为存储为类数据成员的引用将占用内存向上空间。
  • 在使用引用作为参数的情况下,堆栈上会有空间供它使用。
  • @RandyKamradtSr.:不,不一定。电脑没那么简单。可以内联函数并优化整个引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多