【问题标题】:Dereferencing pointer with same adress returns different result取消引用具有相同地址的指针返回不同的结果
【发布时间】:2015-07-24 13:31:59
【问题描述】:

这是我的代码:

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

using namespace std;

double Calc_H(double Q, double Head, double *constants)
{
    return (constants[0] * pow(Q, 4) + constants[1] * pow(Q, 3) + constants[2] * pow(Q, 2) + constants[3] * Q + constants[4] - Head);
}

double Calc_dH(double Q, double *constants)
{
    return (4 * constants[0] * pow(Q, 3) + 3 * constants[1] * pow(Q, 2) + 2 * constants[2] * Q + constants[3]);
}

double NewtonRaphson(double Head, double first_guess, double max_error, double * constants)
{
    double Q_iter = first_guess;
    int iter_counter = 1;
    cout << constants << endl << constants[0] << endl << constants[1] << endl;
    while (abs(Calc_H(Q_iter, Head, constants)) > max_error || iter_counter > 1000)
    {
        Q_iter = Q_iter - Calc_H(Q_iter, Head, constants) / Calc_dH(Q_iter, constants);
        iter_counter++;
    }
    return Q_iter;
}

double * Calc_constants(double freq)
{
    double * pointer;
    double constants[6];
    constants[0] = -1.2363 + 2.3490 / 10 * freq - 1.3754 / 100 * pow(freq, 2) + 2.9027 / 10000 * pow(freq, 3) - 2.0004 / 1000000 * pow(freq, 4);
    constants[1] = 1.9547 - 4.5413 / 10 * freq + 3.5392 / 100 * pow(freq, 2) - 8.1716 / 10000 * pow(freq, 3) + 5.9227 / 1000000 * pow(freq, 4);
    constants[2] = -5.3522 - 4.5413 / 10 * freq - 1.3311 / 100 * pow(freq, 2) + 4.8787 / 10000 * pow(freq, 3) - 4.8767 / 1000000 * pow(freq, 4);
    constants[3] =  3.8894 / 100 + 3.5888 / 10 * freq + 1.0024 / 100 * pow(freq, 2) - 5.6565 / 10000 * pow(freq, 3) + 7.5172 / 1000000 * pow(freq, 4);
    constants[4] = -8.1649 + 5.4525 / 10 * freq - 3.2415 / 100 * pow(freq, 2) + 8.9033 / 10000 * pow(freq, 3) - 9.0927 / 1000000 * pow(freq, 4);
    constants[5] =  2.1180 / 10 + 5.0018 / 100 * freq + 6.0490 / 1000 * pow(freq, 2) - 1.5707 / 100000 * pow(freq, 3) + 3.7572 / 10000000 * pow(freq, 4);

    pointer = constants;
    return pointer;
}

int _tmain(int argc, _TCHAR* argv[])
{

    double * constants;
    //Determine constants based on freq (see manual pump)
    double freq;
    cin >> freq; 
    double head;
    cin >> head;
    constants = Calc_constants(freq);
    cout << constants[0] << endl << constants[1] << endl << constants << endl;
    cout << NewtonRaphson(head, 0, 0.001, constants) << endl;
    cin >> freq;    
    return 0;
}

函数Calc_constants 返回一个指向计算值数组的指针。 到目前为止一切顺利。

函数NewtonRaphson 将指向该数组的指针作为参数。 在此函数中取消引用此指针时,它会为 constants[0]constants[1] 返回不同的结果。我觉得这很奇怪,因为指针“指向”的地址是相同的。

为了澄清这是输出(cout):

-0.09505
2.6008
OOD6F604
00D6F604
-9.25596e+0.61
-9.25596e+0.61
-1.08038e-0.62

【问题讨论】:

标签: c++ dereference


【解决方案1】:
double * Calc_constants(double freq)
{
    double * pointer;
    double constants[6];

Calc_constants 在它的栈上为这个数组分配内存,而不是在堆上。 当这个函数返回时,这块内存可能被分配用于其他目的,因此不应该在这个函数之外访问。 正因为如此,当指针被返回,并在以后使用时,会导致不可预知的结果。

constants 数组需要在 main 或 heap 中分配,因此它的生命周期对于这种使用来说足够长。

在这个while循环条件下,

while (abs(Calc_H(Q_iter, Head, constants)) > max_error || iter_counter > 1000)

我猜,应该是 iter_counter

【讨论】:

  • 谢谢,我会尽力解决这个问题....再次感谢您纠正另一个错误:)
【解决方案2】:

您的代码中没有多少 C++。首先,让我们删除非标准的东西:

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

应该变成:

#include <math.h>
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])

应该变成:

int main()

然后到处都是 C 样式的数组。你不想那样做。使用std::arraystd::vector,问题就会自行消失。

这是std::vector 的示例:

#include <math.h>
#include <iostream>
#include <vector>

double Calc_H(double Q, double Head, std::vector<double> const& constants)
{
    return (constants[0] * pow(Q, 4) + constants[1] * pow(Q, 3) + constants[2] * pow(Q, 2) + constants[3] * Q + constants[4] - Head);
}

double Calc_dH(double Q, std::vector<double> const& constants)
{
    return (4 * constants[0] * pow(Q, 3) + 3 * constants[1] * pow(Q, 2) + 2 * constants[2] * Q + constants[3]);
}

double NewtonRaphson(double Head, double first_guess, double max_error, std::vector<double> const& constants)
{
    double Q_iter = first_guess;
    int iter_counter = 1;
    std::cout << constants.data() << std::endl << constants[0] << std::endl << constants[1] << std::endl;
    while (abs(Calc_H(Q_iter, Head, constants)) > max_error && iter_counter < 1000)
    {
        Q_iter = Q_iter - Calc_H(Q_iter, Head, constants) / Calc_dH(Q_iter, constants);
        iter_counter++;
    }
    return Q_iter;
}

std::vector<double> Calc_constants(double freq)
{
    std::vector<double> constants(6);
    constants[0] = -1.2363 + 2.3490 / 10 * freq - 1.3754 / 100 * pow(freq, 2) + 2.9027 / 10000 * pow(freq, 3) - 2.0004 / 1000000 * pow(freq, 4);
    constants[1] = 1.9547 - 4.5413 / 10 * freq + 3.5392 / 100 * pow(freq, 2) - 8.1716 / 10000 * pow(freq, 3) + 5.9227 / 1000000 * pow(freq, 4);
    constants[2] = -5.3522 - 4.5413 / 10 * freq - 1.3311 / 100 * pow(freq, 2) + 4.8787 / 10000 * pow(freq, 3) - 4.8767 / 1000000 * pow(freq, 4);
    constants[3] =  3.8894 / 100 + 3.5888 / 10 * freq + 1.0024 / 100 * pow(freq, 2) - 5.6565 / 10000 * pow(freq, 3) + 7.5172 / 1000000 * pow(freq, 4);
    constants[4] = -8.1649 + 5.4525 / 10 * freq - 3.2415 / 100 * pow(freq, 2) + 8.9033 / 10000 * pow(freq, 3) - 9.0927 / 1000000 * pow(freq, 4);
    constants[5] =  2.1180 / 10 + 5.0018 / 100 * freq + 6.0490 / 1000 * pow(freq, 2) - 1.5707 / 100000 * pow(freq, 3) + 3.7572 / 10000000 * pow(freq, 4);

    return constants;
}

int main()
{
    //Determine constants based on freq (see manual pump)
    double freq;
    std::cin >> freq; 
    double head;
    std::cin >> head;
    std::vector<double> constants = Calc_constants(freq);
    std::cout << constants[0] << std::endl << constants[1] << std::endl << constants.data() << std::endl;
    std::cout << NewtonRaphson(head, 0, 0.001, constants) << std::endl;
    std::cin >> freq;    
    return 0;
}

(我还将while 循环修改为我猜你想要的。)

如您所见,元素访问的语法与 C 数组相同。使用data() 获得指向std::vector 封装的数据的指针。我添加了这个,因为您的原始代码打印了数组的地址;对于此类应用程序,您在实际代码中很少需要 data()


现在,就您的原始代码而言:

double * Calc_constants(double freq)
{
    double * pointer;
    double constants[6];
    // ...    
    pointer = constants;
    return pointer;
}

这只会产生未定义的行为constants 是一个局部变量。您在此处创建的六个元素在函数返回时被销毁,但您保留了指向它们的指针。如果您稍后尝试取消引用该指针(如您所做的那样),C++ 语言不保证会发生什么。运气好的话,程序会立即崩溃,向您显示存在严重错误,而不是生成无意义的输出。

你也有点不走运,没有得到编译器警告。如果您没有使用多余的 pointer 变量,那么您可能会收到警告(至少对于 VC 2013)。

简单示例:

double * Calc_constants()
{
    double constants[6];
    return constants;
}

int main()
{
    double* ptr = Calc_constants();
}

VC 2013 警告:

warning C4172: returning address of local variable or temporary

使用std::vector,数据在内部分配,以便您可以安全地返回对象。您可以像简单的ints 一样安全地使用标准容器对象,而不会在您的代码中散布原始指针的复杂性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2018-02-20
    • 2013-11-06
    • 2022-06-30
    • 1970-01-01
    相关资源
    最近更新 更多