【问题标题】:Can's seems to use return pointer to double for printing value correctly with coutCan's 似乎使用返回指针加倍以使用 cout 正确打印值
【发布时间】:2018-05-03 13:24:05
【问题描述】:

如果我使用 printf 而不是正确打印值,我无法打印以筛选返回的指针指向的值,以使用 cout 在函数内部声明它也正确打印,如果我调试我看到指向 double 的指针正确返回了它的值(注意我指向的是静态而不是本地),无法理解这里的代码有什么问题(在 Visual Studio 2017 社区版中成功编译)。

#include "stdafx.h"
#include <iostream>

using namespace std;

const double VAT=0.17;

double * addVAT(static double sum)
{
    sum = sum + (sum*VAT); 
    return &sum;
}


int main()
{
    double total = 120;
    double *totalWithVat;
    cout << "Type the total before VAT:";
    cin >> total;
    totalWithVat = addVAT(total);
    printf("The total with VAT is: %f \n", *totalWithVat);
    cout << *totalWithVat << endl;
}

提前致谢。

【问题讨论】:

  • 我从 VC++ "warning C4042: 'sum': has bad storage class" 得到,这应该是一个错误,真的。您的代码没有按照您的想法执行。
  • addVAT 声明中的这个静态是什么。我不认为它编译
  • 不编译,因为static double sum 是参数的无效存储类。 addVAT 例程返回一个悬空指针。
  • 取消引用悬空指针是未定义的行为。未定义的行为可以做正确的事情,并且可以给出奇怪的输出。

标签: c++ pointers printf cout


【解决方案1】:

你不能将函数参数声明为static,你也不能尝试返回局部变量的指针,但是当函数离开它的作用域时,它的局部变量就不再存在了。如果要在 double 上获取有效指针,则需要通过引用传递 sum:

double * addVAT(double& sum) // takes reference
{
    sum = sum + (sum*VAT); 
    return &sum;
}

但是这个 double * addVAT(double& sum) 函数会改变传递给它的变量,这里的总将在调用方法后改变

int main()
{
    //...
    totalWithVat = addVAT(total);// in addVAT sum will referenced to total from main's scope, so it will return pointer to total

    std::cout << total; // will print the same as totalWithVat
    std::cout << totalWithVat; // will print the same as total, totalWithVat points to total
    //...
}  

如果您不想修改total,则只需按值传递并返回双精度值,如下所示:

double addVAT(double sum) 
{
    sum = sum + (sum*VAT); 
    return sum;
}

【讨论】:

  • 我认为OP不想修改total
  • @Slava 是的,可能最好在不修改总数的情况下使用函数。只是他使用了引用和指针,所以我想他想知道如何使用帮助指针来实现它。我将在我的答案中添加此信息以改进它。谢谢
  • 我使用了静态,因为据我所知静态使函数终止后的其他局部变量存活很长时间,假设保存在堆而不是堆栈上,我错了吗?
  • @Aviad430 是的,静态变量只有一个实例,一直存在到程序结束,但不能作为参数使用。静态变量只初始化一次,所以当你将值传递给函数时,你以后不能再初始化它,不要使用静态作为参数。顺便说一句,我的 gcc 在静态参数上抛出错误,你那里没有错误吗?
  • 没有代码在Visual Studio 2017社区版编译成功。
【解决方案2】:

只需使用常规函数:

double totalWithVAT( double sum )
{
    const double vat = 1.17;
    return sum * vat; 
}

std::cout << "The total with VAT is:" << totalWithVAT( total ) << std::endl;

【讨论】:

    【解决方案3】:

    让我们看看你的addVat 函数。

    double * addVAT(static double sum)
    {
        sum = sum + (sum*VAT); 
        return &sum;
    }
    

    您需要从参数列表中删除static。至少对于 Linux 上的 GCC,这会导致编译错误。当我这样做时,我得到了

    <source>: In function 'double* addVAT(double)':
    
    <source>:8:24: warning: address of local variable 'sum' returned
     [-Wreturn-local-addr]
    
    double * addVAT(double sum) 
                      ~~~~~~~^~~
    Compiler returned: 0
    

    和我预期的差不多。

    在您的main 中有total,它被作为副本传递给addVat,它的名称为sum。所以在内存中(在运行时堆栈上)你有

    主要:总计 main->addVat:sum

    addVat 修改sum 并返回一个指向它的指针。问题是返回时addVat会自动释放包含sum的内存。

    所以现在你有

    主要:总计(未更改) main:totalWithVat -> sum 曾经所在的内存

    这是未定义的行为。它可能会起作用,但其他一些例程也可能会重新使用和修改 sum 曾经所在的内存。这可能就是您所看到的。 printf 很幸运,获得了 sum 的未修改值,而 cout 获得了修改后的值。

    作为您的问题的解决方案,有两种可能性。你可以只修改一个输入值,像这样

    void addVat(double& sum)
    {
        sum += sum*VAT;
    }
    
    double total = 1.0;
    addVat(total);
    // total now ~1.17
    

    或者你可以有两个值而不用担心指针/引用

    double addVat(double sum)
    {
        return sum + sum*VAT;
    }
    
    double total = 1.0;
    double totalWithVat = addVat(total);
    // totalWithVat now ~1.17
    

    【讨论】:

    • 如果一个变量声明为静态,它假设将它的值保存在堆上而不是栈上,一旦函数终止,变量将保持在堆上,没有 static 关键字,变量确实是本地的变量,一旦函数执行完毕就会终止。
    • 你说的是真的,但是函数参数列表不是你可以使用static的地方之一。它可以用于文件范围、函数范围和类范围。在这些情况下,内存不在堆上,而是在另一个内存区域(既不是堆也不是堆栈)。
    【解决方案4】:

    解决方法是从参数中删除 static 并传递指针而不是 static ,奇怪的是旧代码编译并成功使用 printf ,这是适用于 cout 和 printf 的正确代码:

    #include "stdafx.h"
    #include <iostream>
    
    using namespace std;
    
    const double VAT=0.17;
    
    double * addVAT(double *sum)
    {
        *sum = *sum + (*sum*VAT); 
        return sum;
    }
    
    
    int main()
    {
        double varTotal = 0;
        double *total;
        total = &varTotal;
        double *totalWithVat;
        cout << "Type the total before VAT:";
        cin >> *total;
        totalWithVat = addVAT(total);
        printf("The total with VAT is: %f \n", *totalWithVat);
        cout << *totalWithVat << endl;
    }
    

    只要我不在参数列表中放入静态,它就可以正常工作,所以我也可以这样编写代码:

    #include "stdafx.h"
    #include <iostream>
    
    using namespace std;
    
    const double VAT = 0.17;
    
    double * addVAT(double sum)
    {
        static double sumstatic = sum;
        sumstatic = sumstatic + (sumstatic*VAT);
        return &sumstatic;
    }
    
    
    int main()
    {
        double varTotal = 0;
        double total;
        double *totalWithVat;
        cout << "Type the total before VAT:";
        cin >> total;
        totalWithVat = addVAT(total);
        printf("The total with VAT is: %f \n", *totalWithVat);
        cout << "The total with VAT is: " << *totalWithVat << endl;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-10
      • 2018-06-25
      • 2014-09-18
      • 2011-01-05
      • 2018-09-12
      • 1970-01-01
      • 2013-10-28
      相关资源
      最近更新 更多