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

Итак, недавно я наткнулся на следующий фрагмент кода:

struct Student
{
    int *number;
    char *name;
    double *marks;
};

int main(){
    int n;
    Student *s;
    s = new Student;
    cout << "Enter the number of subjects the student learns: ";
    cin >> n;
    s->number= new int;
    s->name=new char[20];
    s->marks=new double[n];
    cout << "Enter the name of the student: ";
    cin >> s->name;
    cout << "Enter the number in class of " << s->name << ": ";
    cin >> *(s->number);
    for (int i = 0 ; i < n ; i++){
        cout << "Enter mark No" << i+1 << " of the student: ";
        cin >> s->marks[i];
    }
}

Когда я работал с одномерными массивами указателей, возникала необходимость дважды использовать разыменование. Один раз, чтобы добраться до n-го указателя массива (в данном случае "s->marks[i]") и второй раз, чтобы получить фактическое значение, на которое указывает, что, как я думал, означало написать его так:

*(s->marks[i])

Это, по-видимому, не нужно, хотя я думал, что это вернет серийный номер памяти, содержащийся в указателе «marks [i]». С другой стороны, необходимо разыменовать указатель «число», который представляет собой единственную переменную:

*(s->number)

Это я прекрасно понимаю.

Может кто-нибудь объяснить мне (или указать на хорошую статью), почему нет необходимости использовать оператор разыменования при работе с динамически размещаемыми массивами указателей, такими как, в данном случае, «метки». Меня также смущает использование указателя массива символов "name", который используется скорее как обычная переменная char.

Заранее спасибо за помощь.

Редактировать, чтобы подвести итог:
Я только сейчас понял, что

/*the following two statements declare an array of pointers hence allow for the
use of double dereference*/
int* marks[n]; //static memory allocation
int** marks=new int*[n]; //dynamic memory allocation

/*the following two statements declare an array of variables hence allow for the
use of only one dereference (just a simple 1 dimensional array)*/
int marks[n]; //static memory allocation
int* marks=new int[n]; //dynamic memory allocation


Я думал, что имею дело с чем-то похожим на первую пару утверждений. На самом деле мне пришлось иметь дело со второй парой.


person Adam Payne    schedule 02.05.2014    source источник
comment
Возможно, было бы легче понять, если бы объект Student не выделялся динамически без необходимости. Это плохой код, не воспринимайте его как пример того, как все делается.   -  person jrok    schedule 02.05.2014


Ответы (2)


s->marks — это указатель на первый элемент массива double.

s->marks + i — это указатель на ith элемент.

*(s->marks + i) разыменовывает его, чтобы получить сам элемент double.

s->marks[i] — это удобный способ написать *(s->marks + i). Он включает в себя операцию разыменования, поэтому нет необходимости в еще одной операции.

person Mike Seymour    schedule 02.05.2014
comment
да, но метки — это массив указателей, поэтому я подумал, что s-›marks[i] вернет указатель, а не двойную переменную - person Adam Payne; 02.05.2014
comment
@AdamPayne: Нет, это указатель на (первый элемент) массива double. Указатель на массив указателей будет выглядеть как double**. - person Mike Seymour; 02.05.2014
comment
@AdamPayne marks — это не массив, это всего лишь один указатель на double. Он сделан так, чтобы указывать на динамически выделяемый массив double. - person juanchopanza; 02.05.2014

Предположим, что у вас есть

int x = 10;
int *p = &x;

затем выражение

*p = 20;

эквивалентно выражению

p[0] = 20;

Относительно вашего кода вы могли бы написать

cin >> s->number[0];

вместо

cin >> *(s->number);

Так же, как вы могли бы написать

cin >> *( s->marks + i );

вместо

cin >> s->marks[i];

Согласно стандарту С++

Выражение E1[E2] идентично (по определению) выражению *((E1)+(E2))

Снова возвращаясь к вашему выражению кода

cin >> *(s->number);

можно записать как

cin >> *(s->number + 0);

то есть

cin >> s->number[0];
person Vlad from Moscow    schedule 02.05.2014