Вы используете плохое соглашение для управления переменной userArrayLength
.
Поначалу люди часто находят раздражающим в C то, что он использует массивы на основе 0, но причина, по которой C выбрал массивы на основе 0, в том, что это делает его очень простым, внутренне непротиворечивый, избегающий ошибок набор идиом для управления такими динамическими массивами, как ваш.
Первый вопрос, который нужно задать, если ваш userArray
изначально пуст (как, конечно, он есть), почему вы инициализируете его размер как userArrayLength = -1
? (И я знаю ответ, но, как я собираюсь показать, перестановка других частей программы чуть-чуть позволит нам убрать этот хак.)
Гораздо лучше инициализировать userArrayLength = 0
и переставить программу так, чтобы userArrayLength
всегда содержал количество элементов в массиве - не на один больше или на один меньше, или что-то подобное .
Я рекомендую внести следующие изменения:
- Инициализировать
userArrayLength = 0
.
- Когда вы решите, нужно ли вам перераспределять, измените
>
на >=
, то есть проверьте, *userArrayLength >= *userArrayAvailable
.
- При сохранении данных в массиве перемещайте шаг приращения
(*userArrayLength)++
после того, как сохранит новый элемент в массиве.
- В
listArray
перейдите от 0 до единицы меньше userArrayLength
, написав for (size_t i = 0; i < userArrayLength; i++)
.
С этими изменениями ваша программа работает для меня.
Весь смысл этого упражнения состоит в том, чтобы имело смысл определение и использование userArrayLength
переменной . Если предполагается, что он содержит длину userArray
, тогда пусть фактически содержит точную длину userArray
, не нужно всегда помнить, что он всегда на единицу меньше или что-то в этом роде. (Технический термин для этого пытается поддерживать хороший инвариант цикла .)
Если вы работаете с массивами в C - любого типа массивов, статически или динамически размещаемых - вот некоторые правила, которым вы должны следовать. (Я не уверен, что эти правила записаны где-либо, и некоторые люди будут утверждать, что они являются просто «идиомами» или «соглашениями», но каждый компетентный программист на С согласится, что именно так вы должны это делать, подавляющее большинство времени, если у вас нет действительно веской исключительной причины поступать иначе. Другими словами, они могут быть и правилами.)
- Всегда используйте массивы на основе 0.
- Если у вас есть переменная, которая отслеживает, какая часть массива используется в данный момент, и если массив изначально пуст, всегда инициализируйте переменную count в 0.
- Когда вы сохраняете новый элемент в массиве, всегда увеличивайте переменную "count" после , когда вы сохраняете новый элемент. А так как вы используете массивы на основе 0, правильный индекс, который нужно использовать для хранимого элемента, - это именно ваша переменная "count" (не более 1, не менее или что-то не так запутанное).
- Если вы используете динамически размещенный массив и тестируете, нужно ли увеличивать массив перед сохранением нового элемента, (a) сделайте этот тест до , чтобы сохранить новый element, и (b) используйте
>=
тест между вашей переменной "count" и переменной, которая отслеживает выделенный в данный момент размер. (И, конечно, переменная, которая отслеживает выделенный в данный момент размер, должна отслеживать выделенный в настоящее время размер, а не на один больше или на один меньше.)
- Когда вы перебираете массив, всегда используйте идиоматический цикл
for(i = 0; i < N; i++
.
И если мне кажется, что я слишком много делаю с этими "правилами", вот правдивая история. Я работал над этим ответом около 20 минут, и я до сих пор не знаю, в чем заключалась ошибка в исходной программе. Я просто слишком ленив, чтобы понять это. Я сразу заметил нестандартное использование userArrayLength
, и это сделало программу слишком сложной для меня, чтобы думать о ней. Поэтому я быстро изменил программу, чтобы использовать «правильные» идиомы, и, конечно же, проблема ушла.
Так что это показывает преимущество этих "правил".Да, я согласен, слепое следование правилам может быть опасным.Да, я согласен, возможно, было бы поучительно выяснить, почему оригинальная программа, с ее нестандартным использованием, имела проблему, которую она сделала.Но если у меня нет времени, чтобы сделать это, просто переход на принятую идиому (которую я знаю , из многолетнего опыта работы с ней, всегда работает) волшебным образом устраняет ошибку, и я могудвигаться дальше.
Еще один момент.Мое «правило 3» гласит: «всегда увеличивайте переменную count после того, как вы сохраните новый элемент».Это означает, что у вас часто будет такое выражение, как
array[i++] = newelement;
Главное, на что нужно обратить внимание, это то, что постфиксная форма ++
- это именно то, что вам нужно, и использование префиксной формы array[++i]
будетбыть очень, очень неправильным.
(В вашем случае, поскольку у вас был массив структур с несколькими элементами для назначения, использование ++
не так уж естественно, если только вы не позаботились только о том, чтобы использовать его напоследнее из нескольких заданий.)
Наконец, также полезно поработать над правилами, которые были бы , если бы массивы C были основаны на 1.Я не собираюсь удлинять этот слишком длинный ответ, перечисляя их, но на самом деле они не так уж и плохи.(На самом деле, я мог бы преувеличить еще в начале этого ответа, когда сделал лысое утверждение о «причине, по которой C выбрал массивы на основе 0».) Но - назовите меня сумасшедшим или безнадежным C nurd - я нахожу этоИнтересно, что если вы когда-нибудь вставите в массивы на основе 1, форма автоинкремента с префиксом , то есть array[++i] = newelement
, окажется правильным выбором.