Путаница с экземплярами адресов массивов, указателей и памяти в C++

Я учусь и немного играю с указателями и адресами памяти.

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

Мне бы очень хотелось знать, почему это происходит, поскольку я думаю, что, вызывая адрес, на который указывает указатель, связанный с массивом, я буду вызывать тот же адрес памяти исходного экземпляра, а не другой адрес массива.

Если с моим вопросом возникнет какая-либо путаница или недопонимание, пожалуйста, не стесняйтесь спрашивать что-нибудь, чтобы понять мою проблему. Я действительно хочу знать, почему это происходит.

Код:

#include<iostream>

#include<string.h>

using namespace std;

class Student {
    int age;
    string name;

    // methods and public variables
    public: Student(int _age, string _name) {
        this -> age = _age;
        this -> name = _name;
    }

    // getters & setters not appearing in this problem
};

int main() {

    Student a1(12, "qwe");
    Student a2(15, "rty");
    Student a3(17, "zxc");
    Student * p = & a1;

    // array of instances
    Student students[] = {
        a1,
        a2,
        a3
    };

    // arrays with pointers
    Student * studentPtr1 = students;
    Student * studentPtr2 = & students[0];

    // this two are the same memory addres
    cout << "&a1 --> " << & a1 << endl;
    cout << "p --> " << p << endl;
    // the rest of these memory addresses are different from a1 but are the same memory address as each other
    cout << "&(students[0]) --> " << & (students[0]) << endl;
    cout << "&(students) :" << & (students) << endl;
    cout << "&(*studentPtr1) --> " << & ( * studentPtr1) << endl;
    cout << "&(*studentPtr2) --> " << & ( * studentPtr2) << endl;
    cout << "studentPtr2 --> " << studentPtr2 << endl;

    // if students[0] is a1 why if a try to get his memory address i get a different one ?.
    // &(students[0]) == &a1 ---> false (why??).

    return 0;
}

Выход

&a1 --> 0x7ffeb1d77e30  
p --> 0x7ffeb1d77e30  
&(students[0]) --> 0x7ffeb1d77ec0  
&(students) :0x7ffeb1d77ec0  
&(*studentPtr1) --> 0x7ffeb1d77ec0  
&(*studentPtr2) --> 0x7ffeb1d77ec0  
studentPtr2 --> 0x7ffeb1d77ec0  

какой еще результат вы ожидали и почему?

463035818_is_not_an_ai 16.07.2024 21:08

объект, хранящийся в массиве, не может быть тем же объектом, которого нет в массиве. С++ имеет семантику значений. Student students[] = { a1, a2, a3 }; делает копии

463035818_is_not_an_ai 16.07.2024 21:10

ОТ: std::string из <string>. <string.h> это нечто совершенно другое

463035818_is_not_an_ai 16.07.2024 21:11

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

user4581301 16.07.2024 21:37

если студенты[0] равны a1... Это не так. Это копия А1.

Eljay 16.07.2024 21:53

Эта функция-член deleteStudent — не очень хорошая идея. Если у вас есть указатель на объект Student, вы обычно удаляете объект Student с помощью delete ptr;.

Pete Becker 16.07.2024 22:01

Какая ссылка научила вас использовать синтаксис this->? Вам это не нужно. Если вы собираетесь его использовать, вам следует применять его повсюду; быть последовательным. Ваш конструктор должен использовать список инициализации вместо this->.

Thomas Matthews 16.07.2024 22:03

Ваш деструктор должен быть пустым. У вас нет динамических переменных и ничего, что можно было бы очистить. Оператор delete используется для элементов, размещенных в динамической памяти, которой у вас нет. Вы понятия не имеете, использовал ли Пользователь вашего класса локальное или динамическое размещение. Итак, избавьтесь от утверждения delete this.

Thomas Matthews 16.07.2024 22:05

Вам следует переместить свой метод setName() в раздел геттеров и сеттеров, поскольку это сеттер.

Thomas Matthews 16.07.2024 22:15

К вашему сведению, передайте переменную std::string по ссылке или, если она не записана, передайте ее по ссылке const. В противном случае компилятор создаст копию строки вызывающего объекта и передаст ее вашим методам. Это много ненужного копирования, особенно для больших строк.

Thomas Matthews 16.07.2024 22:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
112
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

student[0] и a1 имеют одинаковое значение, это правда. Но они хранятся в разных местах, поэтому и адреса у них разные.

Вот еще один пример

int a = 1;
int b = 2;
int c = 3;
int student[3] = { a, b, c };

Теперь student[0] == a но &student[0] != &a. Тот факт, что student[0] и a имеют одинаковое значение, не означает, что у них одинаковый адрес. Это (я надеюсь) очевидно, когда a и student[0] являются целыми числами, но это так же верно, когда они являются объектами.

или даже проще int b = a;

463035818_is_not_an_ai 16.07.2024 23:51

Другие вопросы по теме