Лучшие практики для обработки массивов переменного размера в c / c ++?
Автор вопроса: KPexEAОтветов: 9
Если у меня есть массив фиксированного размера, в зависимости от того, как он определен и используется, я обычно использую один из двух способов ссылки на него.
Тип массива 1: поскольку это фиксированный размер на основе определения, я просто использую это определение во всех своих циклах, ссылающихся на него.
#define MAXPLAYERS 4
int playerscores[MAXPLAYERS];
for(i=0;i<MAXPLAYERS;++i)
{
.... do something with each player
}
Тип массива 2: поскольку этот массив может расти по мере добавления в него элементов, я использую sizeof для подсчета количества записей в нем. Размер будет преобразован компилятором в константу, так что это не должно повлечь за собой каких-либо штрафов во время выполнения.
typedef struct
{
fields....
}MYSTRUCT_DEF;
MYSTRUCT_DEF mystruct[]={
{entry 1},
{entry 2},
{entry 3...n}
};
for(i=0;i<(sizeof(mystruct)/sizeof(MYSTRUCT_DEF));++i)
{
..... do something with each entry
}
Есть ли более элегантное решение для обработки массивов, не доходя до конца и не останавливаясь слишком рано. Мысли? Комментарии?
Обратите внимание, что это не массив переменного размера в обычном понимании этого термина (где количество элементов меняется во время выполнения). Michael Burr 10.10.2008
Если вы используете C ++, вам действительно следует использовать один из контейнеров STL. В противном случае удалите тег C ++. Хотя C ++ и C полупортативны, это не одно и то же. mdec 10.10.2008
Это будет работать в обоих случаях, независимо от типа элемента массива:
#define ARRAY_COUNT(x) (sizeof(x)/sizeof((x)[0]))
...
struct foo arr[100];
...
for (i = 0; i < ARRAY_COUNT(arr); ++i) {
/* do stuff to arr[i] */
}
Ответ 2 · рейтинг 5 · Michael Burr
В C ++ просто используйте векторный класс.
Если по какой-то причине вы не можете этого сделать, то существуют макросы, которые вам нужны. См. Этот ответ, чтобы узнать о наборе макросов из winnt.h, которые работают на C и даже безопаснее на C ++:
// crt_countof.cpp
#define _UNICODE
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
int main( void )
{
_TCHAR arr[20], *p;
printf( "sizeof(arr) = %d bytes\n", sizeof(arr) );
printf( "_countof(arr) = %d elements\n", _countof(arr) );
// In C++, the following line would generate a compile-time error:
// printf( "%d\n", _countof(p) ); // error C2784 (because p is a pointer)
_tcscpy_s( arr, _countof(arr), _T("a string") );
// unlike sizeof, _countof works here for both narrow- and wide-character strings
}
Часто вы можете найти по крайней мере одно поле, которое никогда не _2 _ / _ 3_ для обычных элементов, а если нет, вы можете использовать другое специальное значение END.
В коде, который я пишу, все, что связано с массивами размера времени компиляции, выполняется с помощью макроса, такого как ARRAY_COUNT из ответа Checkers, а массивы размера времени выполнения всегда поставляются со счетчиком размера в структуре с массивом.
struct array_of_stuff {
struct stuff *array;
int count; /* number of used elements */
int length; /* number of elements allocated */
};
Поле length позволяет легко изменять размер.
Ответ 5 · рейтинг 1 · Paul Nathan
Для C я бы предложил realloc, чтобы динамически вводить новые переменные. Если вы делаете что-то статически, я бы посоветовал придерживаться #define. Я не уверен, что назвал бы это лучшей практикой, но сегодня я бы практиковал это именно так.
Лучшая практика C ++ - использовать stl :: vector. Ссылка здесь
Ответ 6 · рейтинг 1 · Nick
Я почти всегда использую класс-оболочку (MFC CArray, stl vector и т. Д.), Если нет особой причины. Там не так много накладных расходов, вы получаете много проверок отладки, вы можете динамически изменять размер, легко получить размер и т. Д.
Ответ 7 · рейтинг 1 · paercebal
Для C ++ с использованием std :: vector
Нет смысла использовать C-массив. Std :: vector имеет (почти) ту же производительность, что и массив C, и он будет:
расти по мере необходимости
знать его размер
убедитесь, что вы действительно обращаетесь к правильной памяти (т.е. он может вызвать исключение, если вы выйдете за его пределы)
И это даже без учета общего алгоритма, связанного с std :: vector.
Теперь, используя C
Вы можете написать это несколько лучше, по крайней мере, двумя способами. Во-первых, замена определения истинной постоянной переменной:
// #define MAXPLAYERS 4
const unsigned int MAXPLAYERS = 4 ;
int playerscores[MAXPLAYERS];
for(i=0;i<MAXPLAYERS;++i)
{
.... do something with each player
}
Использование переменной true обеспечит вам несколько большую безопасность типов и не загрязнит глобальную область видимости. Чтобы минимизировать зависимости, вы даже можете объявить переменные в заголовке и определить их в источнике:
/* header.h */
extern const unsigned int MAXPLAYERS ;
extern int playerscores[] ;
/* source.c */
const unsigned int MAXPLAYERS = 4
int playerscores[MAXPLAYERS];
/* another_source.c */
#include "header.h"
for(i=0;i<MAXPLAYERS;++i)
{
.... do something with each player
}
Таким образом, вы сможете изменить размер массива в одном источнике без необходимости перекомпиляции всех источников, использующих его. Обратной стороной является то, что MAXPLAYERS больше не известен во время компиляции (но действительно ли это недостаток?)
Обратите внимание, что ваш второй тип массива не может расти динамически. Размер sizeof (по крайней мере, в C ++) оценивается во время компиляции. Для растущих массивов malloc / realloc / free - это путь в C, а std :: vector (или любой другой общий контейнер STL) - это способ пойти в C ++.
Ответ 8 · рейтинг 1 · xtofl
Не забудьте также прочитать ответы на этот вопрос - многие решения проблема с размером массива, связанная с переносимостью.
Мне особенно нравится _countof (ср. Ответ Брайана Р. Бонди) - Пулитцера для изобретателя с таким именем!
Ответ 9 · MSalters
Дополнение к ответам на данный момент, если вы используете массивы T [] в C ++: используйте вывод аргументов шаблона, чтобы определить размер массива. Намного безопаснее:
Ваше sizeof(mystruct)/sizeof(MYSTRUCT_DEF) выражение завершится неудачно, если вы измените mystruct на malloc'ed / new'ed MYSTRUCT_DEF*. Затем sizeof(mystruct) становится sizeof(MYSTRUCT_DEF*), что часто меньше sizeof(MYSTRUCT_DEF), и у вас будет счетчик циклов 0. Может показаться, что код просто не выполняется, что может вызывать недоумение. Объявление шаблона выше выдаст вам явную ошибку компилятора ("mystruct не является массивом").