Указатель неправильно прокручивает объекты

Я студент университета и пытаюсь решить задание на С++, данное мне профессором. Прошу прощения за мой английский. Короче говоря, мне нужно управлять определенным количеством объектов (одного типа) без использования массивов, а только с помощью указателей. Речь идет об объектах типа «Дом».

Я создаю указатель на «Дом» и с помощью цикла указываю указатель на новый объект типа «Дом», инициализированный переменными, введенными пользователем. Затем я двигаю указатель и начинаю снова.

House* housePtr;

cout<<"We start building houses, you will have to build 4.\n";

for (auto i=0; i<4; ++i, ++housePtr)
{
    int r, d;

    cout<<"\nLet's build the number "<<i+1<<endl;
    cout<<"How many rooms must it have?\n";
    cin>>r;
    cout<<"\nHow far is it from the center?\n";
    cin>>d;

    housePtr= new House(r, d);

}

Проблема возникает, когда я прокручиваю объекты, на которые указывает указатель. Например, чтобы распечатать значения, которыми обладают созданные мной объекты.

Предыдущий цикл for оставляет мне указатель на позицию рядом с последним созданным объектом. Итак, с помощью цикла for я возвращаю указатель к первому объекту (таким образом, я возвращаю его на 4 шага назад) и на каждой итерации заставляю его печатать адрес памяти, удерживаемый указателем, то есть адрес памяти каждого Дома.

for (auto i=0; i<4; i++, housePtr--)
{
    cout<<endl<<housePtr<<endl;
}

И это вывод этого последнего фрагмента кода:

0x10139c

0x101390

0x101384

0x101378

Первый — это адрес, который не имеет ничего общего с объектами, потому что он присущ положению, следующему за последним объектом. Остальные 3 следующих являются (согласно моей логике) адресами четвертого, третьего и второго домов соответственно.

Снова взяв указатель, для каждого объекта я напечатал его значения, а также адрес

for (auto i=0; i<4; housePtr++, i++)
{
    cout<<"\nThe house "<<i+1<<" has "<<housePtr->getNumOfRooms()<<" rooms and is ";
    cout<<housePtr->getDistanceFromCenter()<<" meters from the center\n";
    cout<<housePtr<<endl;
}

И это вывод:

The house 1 has 190607135 rooms and is 201338508 meters from the center
0x10136c

The house 2 has 7 rooms and is 4 meters from the center
0x101378

The house 3 has 190607135 rooms and is 201338508 meters from the center
0x101384

The house 4 has 5 rooms and is 8 meters from the center
0x101390

Первоначальные входные данные, которые я ввел, следующие:

We start building houses, you will have to build 4.

Let's build the number 1
How many rooms must it have?
8

How far is it from the center?
7

Let's build the number 2
How many rooms must it have?
5

How far is it from the center?
8

Let's build the number 3
How many rooms must it have?
7

How far is it from the center?
4

Let's build the number 4
How many rooms must it have?
5

How far is it from the center?
8

Я не могу понять, почему он не печатает данные правильно и по какой причине на одной итерации печатает данные объекта, а на следующей печатает случайные числа.

В чем проблема?


person Ragnarox97    schedule 02.04.2020    source источник
comment
Я думаю, вы смешиваете концепцию массива и указателя. Вы просто пропускаете указатели снова и снова в цикле.   -  person Cory Kramer    schedule 02.04.2020
comment
Если вы хотите, чтобы они были смежными, вы должны объявить их в массиве или использовать new[]. Вы можете выполнить итерацию, взяв House* = &houses[0];, а затем увеличить его, но вы должны инициализировать в массиве.   -  person JohnFilleau    schedule 02.04.2020
comment
Вы просто сохраняете указатель на последний созданный House в своем housePtr, пропуская (без возможности их возврата) все остальные.   -  person Algirdas Preidžius    schedule 02.04.2020


Ответы (2)


Здесь, когда вы делаете housePtr= new House(r, d);, будет создан новый объект и housePtr будет указывать на это. Теперь, когда вы делаете housePtr++, он будет увеличиваться на размер класса House. Теперь снова, когда вы делаете housePtr= new House(r, d);, будет создан новый объект, и он не обязательно будет последовательным адресом ранее созданного объекта. Это самое важное, о чем нужно позаботиться в C++. C++ предоставляет вам голую память без учета безопасности. Это огромная сила, и, как сказал Человек-паук: «С большой силой приходит большая ответственность». Здесь вам всегда нужно следить за тем, чтобы при динамическом создании объекта всегда сохранялся указатель на этот объект. В противном случае вы никогда не получите этот адрес обратно. И это действительно огромная проблема, называемая memory-leak.

Просто предложение, я думаю, вы, профессор, хотите, чтобы вы использовали связанный список. Если вы используете связанный список, вам не нужно будет создавать какой-то массив указателей, чтобы указывать на все созданные объекты. В связанном lint адрес для всех объектов будет храниться в поле указателя предыдущих узлов.

person Nishant Kathiriya    schedule 02.04.2020

Увеличение указателя, который не является массивом, приведет к тому, что этот указатель будет указывать на неиспользуемую/недопустимую память, что приведет к неопределенному поведению (вот почему вы получаете странные значения). Также перезапись указателя на new каждый раз вызовет утечку памяти. По сути, вы используете свой указатель так, как если бы он был массивом, хотя это не так. Если вам всегда нужно делать 4 House-объекта, делайте это так:

House* housePtr1;
House* housePtr2;
House* housePtr3;
House* housePtr4;

cout<<"We start building houses, you will have to build 4.\n";

int r, d;

cout<<"\nLet's build the number 1"<<endl;
cout<<"How many rooms must it have?\n";
cin>>r;
cout<<"\nHow far is it from the center?\n";
cin>>d;

housePtr1 = new House(r, d);



cout<<"\nLet's build the number 2"<<endl;
cout<<"How many rooms must it have?\n";
cin>>r;
cout<<"\nHow far is it from the center?\n";
cin>>d;

housePtr2 = new House(r, d);



cout<<"\nLet's build the number 3"<<endl;
cout<<"How many rooms must it have?\n";
cin>>r;
cout<<"\nHow far is it from the center?\n";
cin>>d;

housePtr3 = new House(r, d);



cout<<"\nLet's build the number 4"<<endl;
cout<<"How many rooms must it have?\n";
cin>>r;
cout<<"\nHow far is it from the center?\n";
cin>>d;

housePtr4 = new House(r, d);

А затем распечатать значения:

cout<<"\nThe house 1 has "<<housePtr1->getNumOfRooms()<<" rooms and is ";
cout<<housePtr1->getDistanceFromCenter()<<" meters from the center\n";
cout<<housePtr1<<endl;

cout<<"\nThe house 2 has "<<housePtr2->getNumOfRooms()<<" rooms and is ";
cout<<housePtr2->getDistanceFromCenter()<<" meters from the center\n";
cout<<housePtr2<<endl;

cout<<"\nThe house 3 has "<<housePtr3->getNumOfRooms()<<" rooms and is ";
cout<<housePtr3->getDistanceFromCenter()<<" meters from the center\n";
cout<<housePtr3<<endl;

cout<<"\nThe house 4 has "<<housePtr4->getNumOfRooms()<<" rooms and is ";
cout<<housePtr4->getDistanceFromCenter()<<" meters from the center\n";
cout<<housePtr4<<endl;

Я предполагаю, что ваш профессор хочет сказать, что делать все это без массивов - это боль;)

person melk    schedule 02.04.2020