проблема с указателями c ++ в visual studio (но работает в g ​​++) - PullRequest
0 голосов
/ 07 августа 2011

Когда я запускаю следующий код в Microsoft visual studio, он выводит ненужные значения (адреса памяти?), Но когда он запускается в g ++, он выводит то, что я намереваюсь (с некоторыми изменениями, такими как изменение srand). Как мне исправить это для работы в visual studio? У меня всего несколько месяцев опыта в программировании, и эта проблема уже давно меня беспокоит.

class Vehicle
{
    protected:
        int * vin;
        double * gasMileage;

    public:
        Vehicle();
        Vehicle(int v, double g);

        virtual void display(){cout<<"vin: "<<*vin<<endl<<"gasMileage: " <<*gasMileage<<endl;}
        virtual double calcGasUsed(int milesDriven){return *gasMileage * milesDriven;}

        int getVin(){return *vin;}
        double getGasMileage(){return *gasMileage;}

        void changeVin(int newvin) {vin=&newvin;}
        void changeGasMileage(double newGasMileage){gasMileage=&newGasMileage;}
        void drive();
};

class Suv:public Vehicle
{
    protected:
        bool *fourWDStatus;
        double * fourWDGasMileage;

    public:
        Suv();
        Suv(int v, double g,bool status, double fwdg);

        void display();
        double calcGasUsed(Suv&, int milesDriven);
        bool getFourWDStatus(){return *fourWDStatus;}
        double getfourWDGasMileage(){return *fourWDGasMileage;}

        void changeFourWDStatus(bool status) {fourWDStatus=&status;}
        void changeFourWDGasMileage(double newGasMileage){fourWDGasMileage=&newGasMileage;}

};
Vehicle::Vehicle()
{
    this->vin=0000;
    this->gasMileage=00;
}
Vehicle::Vehicle(int v, double g)
{
    this->vin=&v;
    this->gasMileage=&g;
}
Suv::Suv(int v, double g,bool status, double fwdg)
{
    this->vin=&v;
    this->gasMileage=&g;
    this->fourWDStatus=&status;
    this->fourWDGasMileage=&fwdg;
}
Suv::Suv()
{
    this->vin=0000;
    this->gasMileage=00;
    this->fourWDStatus=false;
    this->fourWDGasMileage=00;
}
void Suv::display()
{
    Vehicle::display();
    cout<<"fourWDStatus: "<<*fourWDStatus<<endl<<"fourWDGasMileage: "<<*fourWDGasMileage<<endl;
}
void Vehicle::drive()
{
    int r=rand()%10000;
    cout<<calcGasUsed(r)<<endl;

}
double Suv::calcGasUsed(Suv&, int milesDriven)
{
    double x;
    if (*fourWDStatus== true)
    {
        x= ((*fourWDGasMileage) * (milesDriven));
        return x;
    }
    else
    {
        x=((*gasMileage) * (milesDriven));
        return x;
    }
}

void main()
{
    cout << "test";
    srand(NULL);
    Suv A(300,12.2,false,16.6);
    Suv B(200,15.5,false,20.1);
    B.changeFourWDStatus(true);
    Vehicle C(111,20.5);
    C.drive();
    C.display();
    B.display();
    Vehicle arrOfCars[]={A,B,C};
    A.drive();
    B.drive();
    C.drive();
    system("pause");

}

Ответы [ 4 ]

3 голосов
/ 07 августа 2011

Вы используете указатели, не инициализируя их чем-либо.Беглый взгляд говорит мне, что ни одна из ваших переменных-членов не должна быть указателями, и ни один из ваших аргументов конструктора не должен быть ссылками.В других местах вы назначаете int для int *.Компилятор предупреждал вас?

Еще две странные вещи: зачем использовать четырехзначный 0000 для целочисленного литерала и почему system("pause")?

2 голосов
/ 07 августа 2011

Не храните данные членов вашего класса как указатели.Там нет необходимости для вашего использования.На первый взгляд, я вижу проблему здесь:

void changeGasMileage(double newGasMileage){gasMileage=&newGasMileage;}

Что это делает, это устанавливает gasM Пробег, чтобы указывать на значение, выделенное в стеке.Когда changeGasMileage возвращается, вы больше не знаете, что находится в этой ячейке памяти.Вы можете просто сделать gasMileage значением, а не указателем.В противном случае вам нужно сделать:

void changeGasMileage(double newGasMileage){gasMileage= new double(newGasMileage);}

1 голос
/ 07 августа 2011

Члены Vehicle::vin, Vehicle::gasMileage, а также Suv::fourWDStatus и Suv::fourWDGasMileage не являются правильно инициализированными указателями.

Судя по опубликованному коду, вам будет лучше, если вы поменяете их суказатели на обычные переменные (и соответствующие методы).

РЕДАКТИРОВАТЬ: Если использование указателей является частью присваивания, вы должны правильно их инициализировать.Это означает, в вашем случае, выделение памяти в конструкторах.Это может быть так:

Vehicle::Vehicle()
{
    this->vin = new int(0);
    this->gasMileage = new double(0.0);
}

Vehicle::Vehicle(int v, double g)
{
    this->vin = new int(v);
    this->gasMileage = new double(g);
}

Suv::Suv(int v, double g,bool status, double fwdg) : Vehicle(v, g)
{        
    this->fourWDStatus = new bool(status);
    this->fourWDGasMileage = new double(fwdg);
}

Suv::Suv() : Vehicle(0, 0.0)
{
    this->fourWDStatus = new bool(false);
    this->fourWDGasMileage = new double(0.0);
}
0 голосов
/ 07 августа 2011

Другие считают использование указателей неподходящим для этого сценария.Я согласен.

Кроме того, когда конструктор получает копию - по значению - значение, которое вы берете по адресу, находится в стеке (вызова).Когда этот конструктор завершает работу, локальная переменная уничтожается (обычно нет операции для встроенных типов, int, char, float и т. Д.), И доступ к ним через указатель является «неопределенным поведением».

Почемуэто происходит следующим образом: Неопределенное поведение означает, что что-либо может произойти. Предпочтительно диагностика компилятора, альтернативно сбой или, что еще хуже, видимая как поврежденная информация, но в худшем случае это работает, если совпадениядо более позднего времени - см. также Программирование по совпадению .

Эта область после выхода из конструктора будет открыта для повторного использования при вызове других функций - им потребуется место для хранения их локальных переменных, параметров и адресов параметров / возврата для вызова еще других функций.

По некоторому совпадению, gcc (эта версия, эти флаги компилятора) не перезаписывает это место в стеке для печати значений, поэтому вы читаете те значения, которые вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...