246071-Либерти-Освой-самостоятельно-С-за-21-день (852741), страница 56
Текст из файла (страница 56)
Если будет записано значение в массивTargetArray по адресу, выходящему за пределы этого массива, то значения массивов- часовыхизменятся. Одни компиляторы ведут отсчет по возрастающей от адреса массива, другие — поубывающей. Именно поэтому используется два вспомогательных массива, расположенных пообестороныотцелевогомассиваTargetArray.Встроках19-29проверяетсяравенствонулюзначенийэлементовмассивов-часовых(Test1).Встроке33элементумассиваTargetArrayприсваиваетсязначение20,ноприэтомуказаниндекс25,которомунесоответствуетниодинэлементмассиваTargetArray.В строках 36-38 выводятся значения элементов массива TargetArray (Test 2).
Обратитевнимание, что обрашение к элементу массива TargetArray[25] проходит вполне успешно ивозвращаетсяприсвоенноеранеезначение20.Нокогданаэкранвыводятсязначениямассивовчасовых Sentinel0na и SentinelTwo, вдруг обнаруживается, что значение элемента массива5entinelQneизменилось.Деловтом,чтообращениекмассивуTargetArray[25]ссылаетсянатужеячейку памяти, что и элемент массива SentinelQne[Q].
Таким образом, записывая значения внесуществующий элемент массива TargetArray, программа изменяет значение элемента совсемдругогомассива.Если далее в программе значения элементов массива SentinelOne будут использоваться вкаких-торасчетах,топричинувозникновенияошибкибудетсложноопределить.Вэтомсостоитковарствовводазначенийзапределымассива.В нашем примере размеры массивов были заданы значениями 3 и 25 в объявлениимассивов. Гораздо безопаснее использовать для этого константы, объявленные где- нибудь водномместепрограммы,чтобыпрограммистмоглегкоконтролироватьразмерывсехмассивоввпрограмме.Еще раз отметим, что, поскольку разные компиляторы по-разному ведут отсчет адресовпамяти, результат выполнения показанной выше программы может отличаться на вашемкомпьютере.ОшибкиподсчетастолбцовдлязабораОшибки с записью данных за пределы массива случаются настолько часто, что для нихиспользуетсяособыйтермин—ошибкиподсчетастолбовдлязабора.Такоестранноеназваниебыло придумано по аналогии с одной житейской проблемой — подсчетом, сколько столбовнужновкопать,чтобыустановить10-метровыйзабор,еслирасстояниемеждустолбамидолжнобыть1м.Многиенезадумываясьотвечают—десять.Вотеслибызадумалисьипосчитали,тонашли бы правильный ответ — одиннадцать.
Если вы не поняли почему, посмотрите на рис.12.2.Ошибканаединицуприустановкеиндексавобращениикмассивуможетстоитьпрограммежизни. Нужно время, чтобы начинающий программист привык, что при обращении к массиву,состоящемуиз25элементов,индекснеможетпревышатьзначение24иотсчетначинаетсяс0,анес1.(Некоторыепрограммистыпотомнастолькокэтомупривыкают,чтовлифтенажимаютнакнопку4,когдаимнужноподнятьсянапятыйэтаж.)Примечание:Иногда элемент массива ИмяМассива[0] называют нулевым, а не первым.Но и в этом случае легко запутаться. Если элемент ИмяМассива[0] нулевой, то каким тогдабудет элемент ИмяМассива[1]? Первым или вторым? И так далее... Каким будет элементИмяМассива[24]— двадцать четвертым или двадцать пятым? Правильно будет считатьэлементИмяМассива[0]первым,имеющимнулевойсдвиг.ИнициализациямассиваИнициализацию массива базового типа (например, int или char) можно проводитьодновременно с его объявлением.
Для этого за выражением объявления массива нужноустановить знак равенства (=) и в фигурных скобках список значений элементов массива,разделенныхзапятыми.Например:intIntegerArray[5]={10,20,30,40,50>;В этом примере объявляется массив целых чисел IntegerArray и элементу IntegerArray[0]присваиваетсязначение10,элементуIntegerArray[1]—20Ит.д.Если вы опустите установку размера массива, то компилятор автоматически вычислитразмер массива по списку значений элементов. Поэтому справедливой является следующаязапись:intIntegerArray[]={10.20,30,40,50};Рис.12.2.ОшибкаподсчетастолбовдлязабораВ результате получим тот же массив значений, что и в предыдущем примере.
Если вампотребуетсязатемустановитьразмермассива,обратитеськкомпилятору,используяследующеевыражение:constUSHORTIntegorArrayLength;IntegerArrayLength=sizeof(IntegerArray)/sizeof(IntegerArray[0]);В этом примере число элементов массива определяется как отношение размера массива вбайтах к размеру одного элемента. Результат отношения сохраняется в переменнойIntegerArrayLengthтипаconstUSHORT,котораябылаобъявленастрокойвыше.Нельзя указывать в списке больше значений, чем заданное количество элементов массива,Так, следующее выражение вызовет показ компилятором сообщения об ошибке, посколькумассиву,состоящемуизпятиэлементов,пытаютсяприсвоитьшестьзначений:intIntegerArray[5]={10,20,30,40,50,60);Втожевремяследующеевыражениенебудетошибочным:intIntegerArray[5]={10,20};Значения тех элементов массива, которые не были инициализированы при объявлении, неустанавливаются.
Обычно считают, что значения неинициализированных элементов массиванулевые. В действительности они могут содержать любой мусор — данные, которые когда-торанее были занесены в эти ячейки памяти, что, в свою очередь, может оказаться источникомошибки.Рекомендуется:Позвольте компилятору самостоятельно вычислять размер массива.Присваивайте массивам информативные имена, раскрывающие их назначение.
Помните, чтодляобращениякпервомуэлементумассиваследуетуказатьиндекс0.Нерекомендуется:Незаписывайтеданныезапределымассива.ОбъявлениемассивовМассиву можно присвоить любое имя, но оно должно отличаться от имени всех другихпеременных и массивов в пределах видимости зтого массива. Так, нельзя объявить массивmyCats[5],есливпрограммеранееужебылаобъявленапеременнаяmyCats.Размермассиваприобъявленииможнозадатькакчислом,такиспомощьюконстантыилиперечисления,какпоказановлистинге12,3.Листинг12.3.Использованиеконстантыиперечисленияприобъявлениимассива1://Листинг12.3.2://Установкаразмерамассиваспомощьюконстантыиперечисления3:4:#include<iostream.h>5:intmain()6:{7:enumWeekDays{Sun,Mon,Tue,8:Wed,Thu,Fri,Sat,DaysInWeek};9:intArrayWeek[DaysInWeek]={10,20,30,40,50,60,70}10:11:cout<<"ThevalueatTuesdayis"<<ArrayWeek[Tue];12:return0;13:}Результат:ThevalueatTuesdayis30Анализ: В строке 7 объявляется перечисление WeekDays, содержащее восемь членов.Воскресенью(Sunday)соответствуетзначеню0,аконстантеDaysInWeek—значение7.В строке 11 константа перечисления Tue используется в качестве указателя на элементмассива.
Поскольку константе Tue соответствует значение 2, то в строке 11 возвращается ивыводитсянапечатьзначениетретьегоэлементамассиваArrayWeek[2].МассивыЧтобы объявить массив, сначала нужно указать тип объектов, которые будут в немсохранены,затемопределитьимямассиваизадатьразмермассива.Размеропределяет,сколькообъектовзаданноготипаможносохранитьвданноммассиве.Пример1:intMyIntegerArray[90];Пример2:long*Array0fPointersToLogs[100];Чтобы получить доступ к элементам массива, используется оператор индексирования.Пример1:InttheNinethInteger=MyIntegerArray[8];Пример2:long*pLong=Array0fPointersToLogs[8];Отсчетиндексовмассиваведетсяснуля.Поэтому,дляобращениякмассиву,содержащемуnэлементов,используютсяиндексыот0доn-1.МассивыобъектовЛюбойобъект,встроенныйилисозданныйпользователем,можетбытьсохраненвмассиве.Нодляэтогосначаланужнообъявитьмассивиуказатькомпилятору,дляобъектовкакоготипаэтот массив создан и сколько объектов он может содержать.
Компилятор вычислит, сколькопамятинужноотвестидлямассива,основываясьнаразмереобъекта,заданномприобъявлениикласса. Если класс содержит конструктор, заданный по умолчанию, в котором неустанавливаются параметры, то объект класса может быть создан и сохранен в массивеодновременнособъявлениеммассива.Получениедоступакданнымпеременных-членовобъекта,сохраненноговмассиве,идетвдваэтапа.Сначаласпомощьюоператораиндексирования([])нужноуказатьэлементмассива,азатем обратиться к конкретной переменной-члену с помощью оператора прямого обращения кчленукласса(.).Влистинге12.4показаносозданиемассивадляпятиобъектовтипаCAT.Листинг12.4.Созданиемассиваобъектов1://Листинг12.4.Массивобъектов2:3:#include<iostream.h>4:5:classCAT6:{7:public:8:CAT(){itsAge=1;itsWeight=5;}9:~CAT(){}10:intGetAge()const{returnitsAge;}11:intGetWeight()const{returnitsWeight;}12:voidSetAge(intage){itsAge=age;}13:14:private:15:intitsAge;16:intitsWeight;17:};18:19:intmain()20:{21:CATLitter[5];22:inti;23:for(i=0;i<5;i++)24:Litter[i].SetAge(2*i+1);25:26:for(i=0;i<5;i++)27:{28:cout<<"cat#"<<i+1<<":";29:cout<<Litter[i].GetAge()<<endl;30:}31:return0;32:}Результат:cat#1:1cat#2:3cat#3:5cat#4:7cat#5:9Анализ: В строках 5—17 объявляется класс CAT.
Чтобы объекты класса CAT моглисоздаваться при объявлении массива, в этом классе должен использоваться конструктор,заданный по умолчанию. Вспомните, что если в классе создан какой- нибудь другойконструктор, то конструктор по умолчанию не будет предоставляться компилятором и вампридетсясоздаватьегосамим.Первый цикл for (строки 23 и 24) заносит значения возраста кошек в объекты класса,сохраненные в массиве.