Студентка первого курса компьютерных наук, впервые пишу здесь.
У меня есть структура:
struct Student{
string name;
int studentID;
int numTests;
int *testScores = new int [TESTS]; //Access with <variableName>.*(testScores + 1), <variableName>.*(testScores + 2), etc.
int avgScore;
};
У меня возникли проблемы с попыткой понять, как изменить значения в массиве. Наверное, я не могу понять синтаксис.
Вот что я делаю, на правильном ли я пути?
cout << "How many tests did this student take: ";
cin >> numTests;
//iterate numTests amount of times through dynamic array
for (int i = 0; i < numTests; ++i)
{
cout <<"Enter score #" << i + 1 << ": ";
cin >> tempScore;
newStudent.*(testScores + i) = tempScore;
}
Я был бы признателен за любую помощь в определении правильного способа изменения значений массивов.
Я пробовал не использовать значение temp, изменив его на
cin >> newStudent.*(testScores + i);
вместе с
cin >> *newStudent.(testScores + i);
и несколько других вариантов, но я не могу найти правильный способ сделать это. Все еще новичок в работе с кучей.
Access with <variableName>.*(testScores + 1),...
нет, пожалуйста, не делай этого. Вы получаете доступ к элементам через newStudent.testScores[index]
. Но вам действительно не следует ничего из этого делать, используйте std::vector
Я еще ничего не узнал о векторах, хотя продолжаю слышать о них. Я ограничен в своих возможностях использовать такие инструменты, как векторы. Также не очень хорошо описывается проблема, поэтому, если я говорю «ссылка», я могу иметь в виду что-то другое, все еще студент первого курса.
вам нужен лучший учебный материал. Работа с c-массивами — это не то, о чем вы можете догадаться. Слишком много подводных камней. Попробуйте stackoverflow.com/questions/388242/…
Оцените материал для чтения, я изучу его, есть ли какой-нибудь простой способ сделать это?
почему вы ограничены в использовании векторов? Массивы — это очень сложные элементы, от которых вам следует держаться подальше. std::vector
— это то, чему новички могут научиться с первого дня. Чтобы научиться писать правильную небольшую программу с помощью std::vector
, требуется 5 минут, но вы можете потратить всю жизнь на борьбу с c-массивами.
профессор запретил их в инструкциях, но я их еще не выучил
@ 463035818_is_not_an_ai Многие вводные преподаватели информатики запрещают использовать такие вещи, как vector
, пока они не будут введены.
Я рассказал тебе простой способ. Забудьте о Access with <variableName>.*(testScores + 1),...
и используйте []
вот так newStudent.testScores[index]
@Dúthomhas, потому что они не преподают C++. В любом случае, это не класс CS. Вопрос в C++, а не в том, как обмануть студентов и научить их C, заставив их поверить, что это C++.
@463035818_is_not_an_ai Нет, вопросы, ответы на которые вырваны из контекста, имеют бесполезные ответы.
@Dúthomhas контекст имеет динамический массив в качестве члена. В этом контексте std::vector
не вырвано из контекста. Я никогда не утверждал, что «использовать std::vector
» будет полным ответом. Тем не менее, это предложение, которое кто-то должен сделать ОП.
Только что заказал Программирование: принципы и практика использования C++, очень ценю эту ссылку!
А пока вы можете попробовать на Learncpp.com , а также обязательно поищите cppreference для справки (и актуальных примеров). И, наконец, прочитайте Основные рекомендации по C++ (возможно, после прочтения вашей книги), чтобы узнать, как использовать C++ сегодня (что может снова немного отличаться от того, что было несколько лет назад).
Профессор @Noah Stromberg объявил их вне закона в инструкциях — std::vector
официально является частью библиотеки C++ вот уже 26 лет. Вероятно, он старше большинства людей в вашем классе. В наши дни нет смысла не обучать вектору заранее. Вот почему многие начинающие программисты оставляют C++ и начинают изучать Python или какой-либо другой язык — у них нет этих ограничений — они используют то, что есть в языке. предложить им, плюс они гораздо быстрее получают программы, действительно работающие должным образом.
Во-первых, «ссылочный массив» — это удивительный способ описания testScores
. Элемент данных testScores
в вашем struct
имеет тип «указатель на int
» и предположительно указывает на первый элемент массива, который вы выделили с помощью выражения new
.
Во-вторых, вы получаете доступ к элементам этого массива, выполняя
newStudent.testScores[i] = tempScore;
// which is equivalent to ...
*(newStudent.testScores + i) = tempScore;
Вы также можете написать
std::cin >> newStudent.testScores[i];
... обходя необходимость в дополнительной локальной переменной tempScore
.
std::vector
)std::cin
)Спасибо, я знал, что не правильно описал проблему. Я использовал tempScore, чтобы просто проверить и посмотреть, есть ли какая-то разница, она уже была на момент публикации, лол.
«Во-первых, «ссылочный массив» — это удивительный способ описания testScores», извините. Я удалил сюрприз из вопроса. Я просто воздержусь и оставлю вам возможность откатиться назад или изменить свой ответ.
Есть несколько вещей, которые вы должны знать, имея дело с прямым управлением памятью (с использованием new
и delete
) в C++.
Во-первых, это Правило Трех/Пяти/Нуля. По сути, если у вас new
память, вы также delete
должны ее использовать, и вы должны правильно с ней обращаться, когда ваш класс копируется/перемещается.
struct Student
{
int * scores; // This is a pointer (to an array)
int nscores; // Number of elements used in that array
Student(); // Constructor
~Student(); // Destructor
Student( const Student & student ); // Copy constructor
Student( Student && student ); // Move constructor
Student & operator = ( const Student & student ); // Copy Assignment operator
Student & operator = ( Student && student ); // Move Assignment operator
};
Student::Student()
{
scores = new int[ NUM_TESTS ]; // allocate NUM_TESTS elements
nscores = 0;
...
}
Student::~Student()
{
delete [] scores; // clean up!
}
Student::Student( const Student & student )
{
// same as before, but COPY the data!
scores = new int[ NUM_TESTS ]; // allocate NUM_TESTS elements
for (int n = 0; n < student.nscores; n++)
scores[n] = student.nscores[n];
nscores = student.nscores;
}
Student::Student( Student && student )
{
// MOVE the data instead!
scores = student.scores;
student.scores = nullptr;
nscores = student.nscores;
student.nscores = 0;
}
Student & operator = ( const Student & student )
{
// And again, except that we already have an array of
// test scores allocated so we only need to copy them
for (int n = 0; n < student.nscores; n++)
scores[n] = student.nscores[n];
nscores = student.nscores;
...
return *this;
}
Student & operator = ( Student && student )
{
// and again, MOVE the data!
nscores = student.nscores;
student.nscores = nullptr;
nscores = student.nscores;
student.nscores = 0;
return *this;
}
Обратите внимание, что тип указателя на массив — это просто указатель:
int * scores;
И что мы получаем доступ к элементам массива обычным способом:
scores[2] = 12;
Следите за тем, чтобы пользователь (или любая другая часть программы) не вырос nscores
до > NUM_TESTS
.
cout << "How many tests did this student take: ";
cin >> numTests;
if (numTests > NUM_TESTS)
{
cerr << "too many! ack!\n";
return 1;
}
//iterate numTests amount of times through dynamic array
for (int i = 0; i < numTests; ++i)
{
cout <<"Enter score #" << i + 1 << ": ";
cin >> tempScore;
newStudent.scores[i] = tempScore;
}
Если вы знаете, что ваш массив всегда имеет фиксированную длину (как в вашем примере), вам фактически не нужно его динамически выделять.
struct Student
{
int scores[ NUM_TESTS ];
int nscores;
};
Однако вам все равно необходимо правильно инициализировать nscores
в своем конструкторе и позаботиться о том, чтобы не выйти за пределы конца массива.
Очевидно, что ваше задание составлено не так, но в любом случае это полезно знать.
Я предполагаю, что в какой-то момент вам будет поручено увеличить массив, если это необходимо. Для этого требуется еще одно значение члена:
struct Student
{
int * scores; // array of test scores
int nscores; // number of elements used in scores[]
int nscores_available; // size of scores[] array
};
Это немного усложнит ситуацию, но позволит вам делать такие вещи, как создание заполнения большего массива, если текущий слишком мал.
Другими словами, вы заменяете глобальную константу NUM_TESTS
на значение локального члена nscores_available
, которое можно изменить и которое может отличаться в разных Student
.
Впрочем, это на потом.
что вы имеете в виду под «ссылочным массивом»? У вас есть указатель на in как на элемент, инициализированный для указания на первый элемент целочисленного массива. Нет ссылки