2010-02-23 2 views
1

Учитывая это:C++ инициализация массива

typedef struct 
{ 
int x; 
int y; 
} Coordinate; 

Coordinate places[100]; 
  • ли память для 100 координат выделенных автоматически? Или он выделяет один за один раз, когда вы инициализируете каждый элемент массива?

  • Что произойдет, если вы укажете неинициализированные части массива? Это вызывает ошибку?

+0

Память выделяется автоматически, когда вы объявляете места. Если вы выйдете за пределы, вы, вероятно, вызовете ошибку сегментации. – Beta

+2

Поскольку это помечено C++, вам не нужно использовать идиому C typedef. Вместо этого используйте 'struct Coordinate {...};'. Это определяет тип, называемый «Координата» в C++. – Clifford

+0

@Beta, это ответ, а не комментарий. Почему бы вам не ответить на него? – paxdiablo

ответ

0

1/Да, есть распределение. И вызов деструктора и освобождение в конце блока.

2/Все элементы массива инициализируются конструктором по умолчанию (это ошибка времени компиляции, если нет конструктора по умолчанию). Если конструктор по умолчанию не инициализирует что-то, это то же поведение, если этот объект является частью массива или нет (т.е. неопределенное значение, которое может вызвать неопределенное поведение, если они считаны)

+0

Просто уточнить. Все 100 объектов выделяются сразу (или во время компиляции, если массив является глобальным), и сразу по умолчанию вызывается конструктор по умолчанию (или когда программа запускается, если массив является глобальным). Доступ к неинициализированным частям массива (в отличие от частей вне границ) может вызвать или не вызвать ошибку в зависимости от типа доступа. Я считаю, что стандарт предусматривает, что это неопределенное поведение. Как правило, чтение неинициализированного int не приведет к ошибке, тогда как разыменование указателя обычно будет. – Ari

0

сначала: да, область зарезервировано, но его содержание будет недействительно, пока область не инициализировано
вторыми: многие вещи могут случиться, одно Acces нарушения или ничего, но делает систему работать неправильно

+0

Небольшая коррекция второй части ... Адресация неинициализированных частей массива не приведет к нарушению доступа, поскольку выделена память - она ​​может быть просто заполнена данными мусора, которые могут вызывать ошибочное поведение. –

0

память выделяются автоматически в стеке, поэтому вы должны быть осторожны с тем, насколько велики вы делаете массив. Каждая ОС имеет разные размеры стеков, но тем не менее существует предел. Как правило, небольшое количество КБ на поток/процесс.

Когда вы обращаетесь к неинициализированным членам массива, вы будете читать все, что было ранее, из другого фрейма стека или любого случайного мусора на этой странице памяти. Следовательно, его рассмотренная хорошая практика инициализирует массив с помощью memset или инициализатора массива.

0

В вашем примере все экземпляры выделены сразу - все элементы от 0 до 99 включительно действительны. Если бы вы использовали тип с конструктором, все 100 были бы построены.

EDIT - как отмечали другие, только потому, что он построен, не означает, что ничего не было инициализировано. Конструктор по умолчанию для «int» оставляет его нетронутым (ваша работа должна инициализировать его так, как вам хочется). Конструктор по умолчанию для «struct» вызывает конструкторы для своих членов. То есть, построение здесь мало значит, но память выделена и готова для вас (инициализировать и использовать).

Первая неинициализированная «часть массива» не является частью массива - она ​​выходит за пределы. Например ...

Coordinate mistake = places [100]; // Above the upper bound 

Это поведение не определено. Вы можете получить сбой (какое-то связанное с памятью исключение из процессора). Ваша программа может успешно работать, не зная, что она использует недопустимые данные нежелательной почты. В приведенном выше случае, поскольку то, что происходит, довольно очевидно, вы, вероятно, получите предупреждение о компиляторе, но это, как правило, не будет.

Если вы написать в индекс массива недоступный, вы можете быть развращает другие переменные или обратный адрес вашей функции или просто о чем-нибудь, так что поведение всей вашей программы с этого момента не определен , Это является основой одного из самых больших целых классов недостатков безопасности и «эксплойтов».

std :: vector - еще один способ создания массивов. Он не выделяет сразу все элементы - это динамический массив, который позволяет изменять размер (и управляет). Тем не менее, он не будет выходить за пределы индексов больше, чем базовый массив C-стиля.

0

1) Память выделяется как единый непрерывный блок.

2) Если экземпляр статически (то есть не переменная auto), то память должна быть инициализирована равной нулю, в противном случае она будет неинициализирована, а контент не будет определен. Доступ к этим неопределенным значениям не вызывает каких-либо ошибок, если вы читаете мусорные данные и действуете на них, поведение будет определяться полностью недетерминированным контентом и вашим кодом.

Если вы хотите автоматическую инициализацию, вы можете определить конструктор по умолчанию. В C++ структура практически идентична классу (различия отличаются видимостью и наследованием элементов по умолчанию) и могут иметь функции-члены, конструкторы и деструкторы.

2

Сохранение памяти зависит от того, где объявлено объявление массива. Если он объявлен в глобальной области видимости (т. Е. Вне функции), то 800 байтов (при условии, что целое число равно 32 битам) становится доступным для всей программы сразу. Если он находится внутри функции, эти 800 байт выделяются в стеке и недоступны, когда функция завершается.

Так что в вопросе 1: Да, все 100 координат доступны в том же объеме, что и декларация.

Вопрос 2: Вы можете получить доступ ко всем 100 элементам в любое время, но их содержимое будет неинициализировано. Таким образом, безопасно сразу написать все 100 индексов, просто не читайте их, пока вы их не инициализировали.

Если вы хотите инициализировать их всех (скажем, 0,0), то сделать это заявление вместо:

struct Coordinate 
{ 
    int x; 
    int y; 

    Coordinate() : x(0), y(0) { } 
}; 

конечно, это работает только в C++. Если вы пишете код в C, у вас нет возможности автоматически инициализировать элементы в массиве.

Чтение за пределами 0 до 99 даст неопределенное поведение. В лучшем случае среда выполнения обнаружит, что дайте вам ошибку времени выполнения. В худшем случае вы повредите память и не узнаете, пока программа не закончится, пока вы не зададите себе вопрос, где ошибка. Поэтому будьте осторожны и убедитесь, что ваши индексы находятся в пределах.

Общая практика заключается в предоставлении функции доступа к массиву (не обращайтесь непосредственно к массиву), и там вы можете выполнить проверку assert для проверки индекса массива.

удачи

+0

Небольшое примечание. Если массив объявлен в глобальной области видимости, значения int будут инициализированы до 0, даже без конструктора Coordinate(). – MtnViewMark

+0

Также в локальной области действия, но с классом хранения 'static', гарантируется нулевая инициализация. – Clifford

+0

Что касается параграфа «обычная практика», так как это C++, то тип 'std :: vector', доступ к которому осуществляется с помощью функции' at() 'member, а не оператора' [] ', обычно будет лучше (или, по крайней мере, меньше C-like), поскольку он генерирует исключение, если индекс превышает границы. – Clifford

0

Там не было бы никакой разницы в поведении массива на основе типа. Итак, выделение памяти выполняется после создания массива, и когда неинициализированные переменные будут иметь некоторые данные мусора.

Чтобы инициализировать все элементы массива, вы можете создать конструктор по умолчанию для инициализации их до требуемого значения или конструктора с параметрами по умолчанию, где значения могут быть инициализированы до значения, необходимого при отсутствии значений.

Например:

struct Coordinate 
{ 
    int x; 
    int y; 

    Coordinate (int x1 = 0, int y1 = 0) : x(x1), y(y1) { } 
}; 

Это работает с массивами и все значения в массиве будет инициализирован в ноль (0).

Чтобы initilize всех элементов массива примитивного типа данных в ноль (0)

int places[100] = { 0 }; 

Не проверить, работает ли он для определенного пользователя типов, хотя. Вы можете попробовать.