#c
#c
Вопрос:
Я пытаюсь создать массив с переменным количеством строк, но в нем всегда будет 4 столбца. Делает что-то вроде:
int** numGrades = new int* [num_exams];
for (int i = 0; i < num_exams; i)
{
numGrades[i] = new int[4];
}
хороший способ сделать это? Я чувствую, что есть более простой способ, но я не могу придумать ни одного. Кроме того, массив продолжает вызывать у меня утечки памяти, поэтому мне интересно, связано ли это с тем, что я делаю то, чего не должен делать. К вашему сведению, векторы запрещены для этой программы.
Комментарии:
1. Для чего вы будете его использовать?
2. Это часть более крупного задания, в котором я вычисляю оценки учащихся. В этом конкретном массиве будет храниться номер каждой оценки (A, B, C, D, F) на каждом экзамене для любого заданного количества экзаменов.
3. Ответ — НЕТ. Однако, если вы имеете дело с чем-то, что всегда имеет 4
int
, ваше распределение должно бытьint (*numGrades)[4] = new int[num_exams][4];
таким, чтобы обеспечить однократное выделение и однократное освобождение блока памяти (также значительно упрощает перераспределение)4. Я попытался выделить его таким образом, но теперь это не позволит мне передать массив ни одной из моих функций. В нем говорится «аргумент типа int * несовместим с типом int **». Объявляет ли это так, как вы это сделали, что это больше не 2d-массив?
Ответ №1:
Вы могли бы создать массив строк.
struct Row{
int values[4];
};
Row* numGrades = new Row[num_exams];
Комментарии:
1. Будет ли в этом какое-либо реальное преимущество? У меня уже есть это как 2d-массив, но если это стоит изменить, я это сделаю.
2. @aons32 Да, это уменьшило бы потребность в динамических распределениях. Вам не нужно беспокоиться о
num_exams
выделениях, а только об одном. Если векторы не разрешены, это, вероятно, было бы лучшим решением.3. Это, вероятно, также исправило бы странные утечки памяти. Я, вероятно, попробую это завтра.
4. Альтернативы:
new std::array<int,4>[num_exams];
если не все контейнеры STL запрещены или дажеnew int[4 * num_exams];
.5. @aons32 Еще одно преимущество структурного подхода: если каждая строка представляет экзамены для одного учащегося, то вы также можете добавить функции в структуру и делать что-то вроде этого:
for (const Rowamp; student : numGrades) student.calculateAverage();
или, как предложил Дэвид К. Рэнкин, перегрузить operator >> и << для чтения и записи данных учащихся.
Ответ №2:
Может быть, вы можете попробовать это.
typedef int row[4];
//or
using row = int[4];
row *numGrades = new row[num_exams];
Ответ №3:
Выделение некоторого количества массивов фиксированного размера является прекрасным и выгодным во многих случаях.
В дополнение к struct
(что является очень хорошим вариантом), другим вариантом является объявление указателя на массив с фиксированным количеством элементов. Преимущество в том, что у вас есть однократное выделение и однократное освобождение для блока памяти. (как вы делаете с массивом struct) Если вам нужно увеличить блок памяти (с помощью — declare bigger block, скопируйте существующий в больший, удалите существующее перераспределение), это упрощает процесс. В вашем случае:
int (*numGrades)[4] = new int[num_exams][4];
Который выделит num_exams
количество массивов из 4 int
одновременно. Это дает преимущество одного delete[] numGrades;
, когда вы закончите с памятью.
Короткий пример, который использует std::istringstream
для хранения значений примеров для чтения в блок памяти, содержащий массивы фиксированного размера, может быть:
#include <iostream>
#include <sstream>
int main (void) {
std::istringstream iss { "1 2 3 4 5 6 7 8 9" };
int npoints = 3,
(*points)[3] = new int[npoints][3],
n = 0;
while (n < 3 amp;amp; iss >> points[n][0] >> points[n][1] >> points[n][2])
n ;
for (int i = 0; i < n; i )
std::cout << points[i][0] << " " << points[i][1] << " " << points[i][2] << 'n';
delete[] points;
}
(примечание: вам следует избегать использования new
и delete
в пользу контейнера, такого как std::vector, если это не для образовательных целей)
Пример использования / вывода
$ ./bin/newptr2array3
1 2 3
4 5 6
7 8 9
Стоит отметить, что преимущество struct
заключается в том, что это позволит вам перегружать >>
и <<
std::istream
и std::ostream
, чтобы предоставить удобные функции для чтения и записи необходимых вам данных.
В любом случае, указатель на массив фиксированных элементов или создание struct
, а затем массива struct
— это прекрасно.
Ответ №4:
Вы могли бы пропустить цикл for:
int* numGrades = new int[num_exams*4];
int firstElement = numGrades[x];
int secondElement = numGrades[x 1];
int thirdElement = numGrades[x 2];
int fourthElement = numGrades[x 3];
Пропуская цикл for, вы получаете это:
-
Вам не обязательно иметь цикл for для освобождения памяти:
удалить[] numGrades;
-
Куча не так сильно фрагментируется, потому что вы не вызываете «new» так много раз.
НО все зависит от того, для чего вы его используете. В современном C не такая хорошая идея использовать dynamic, но создавать структуру в std ::vector.
Комментарии:
1. Я бы предпочел использовать векторы, но мне это не разрешено. И какой смысл пропускать цикл for?
2. @aons32 Я добавил объяснение, почему пропуск цикла for — хорошая идея.