Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Как создать свой сайт и заработать?" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Программирование с нуля - это совсем просто! 39) Массивы
Информационный Канал Subscribe.Ru |
Программирование с нуля - это совсем просто!39) Массивы
procedure A;
procedure B; Здесь N - разные переменные, хотя и называются одинаково. Существуют они только во время вызова процедуры, и все. И обращаться к ним можно только внутри соответствующей процедуры. И модифицировать их можно лишь из родной подпрограммы, и больше ниоткуда. Подпрограмма - это своего рода отдельная маленькая программа, если вы в разных программах одни и те же названия переменных используете, это не значит, что они как-то связаны. Вот такие записи типично ошибочны:
function dice6: integer;
Что такое здесь n и когда в нее заносится значение? Что из того, что здесь в n что-то записано, эта n ведь нигде не используется. Это все локальные n, за пределами этих процедур они нигде не видны.
* Я вот как параметр использовала sides. И в обработчике кнопки я тоже
переменную sides использовала: n=dice(sides). Нужно ли делать так или лучше другую
переменную использовать типа: В принципе не принципиально :) Паскаль, он всегда считает локальную переменную важнее глобальной. Для наглядности можно разные использовать имена, хотя некоторые как раз любят совпадающие с параметрами. Но это все же не совсем корректно будет. * Насчет типа "логический" - в Си его официально нету (в Си++ последних версий есть - "bool" ), поэтому достаточно типа int. 1 - это истина, 0 - ложь. В Си++ по идее и так можно записывать: bool vivod; Vivod = (Tria == 0) ; // true false * Часто спрашивают про mod ("%" в Си). Это важная и полезная функция, часто применяется, возвращает целый остаток от деления двух целых чисел. Если вам нужен остаток от деления, то используете mod (%), если целая часть - то div (/). 10 div 3 = 3 (в остатке 1) 10 mod 3 = 1 (целый остаток от деления на 3) Последнюю цифру числа можно найти, взяв остаток (mod) от деления на 10. * Чтобы закрыть текущую форму, можно сделать кнопку Выход, а в ее обрабочике записать единственную команду Close; В Си - Close(); В Си нет процедур, а все подпрограммы - функции, поэтому их обязательно надо указывать с круглыми скобками, даже если нету параметров. * Чтобы exe-программу на Паскале/Си можно было переносить на другие компьютеры, надо в меню выбрать Project - Options - вкладка Packages - снять флажок с поля Build with runtime packages и перекомпилировать. Файл ехе будет побольше, но зато переносимым. Этот флажок, когда выключен, говорит, что надо включать все вспомогательные библиотеки в ехе-файл. Подпрограммы можно вкладывать друг в друга.
procedure B;
A; // это вызов процедуры A
N := 2;
A; // еще раз
end;
procedure C;
B;
N := 3;
B;
end;
Вызовите из исходной программы процедуру C и посмотрите, что выведется. В ходе отладки, если встречается строка например B; то чтобы выполнить подпрограмму разом, надо нажать F8, а чтобы спуститься в нее внутрь - F7. * Как отлаживать графические программы? F8 с начала не катит, потому что наш собственный код только в обработчике записан, а все остальное сгенерено автоматически. Надо поставить в своем тексте точку прерывания (клавиша F5), запустить программу на выполнение обычное, дождаться события - когда его отладчик поймает, и продолжить тогда по шагам. Задание N 20. Напишите функцию, возводящую число (первый параметр) в степень (второй параметр). Пользуйтесь только операцией умножения. Задание N 21. Напишите функцию, переводящую сумму в рублях и копейках (два параметра-числа) в строку со словами рублей, копеек в правильных падежах. На базе прежнего задания. Полезно свой собственный код попробовать попеределывать. Кстати, на begin.polubomu.ru Таня опубликовала ваши варианты решения 13 и 14 заданий. С комментариями и уточнениями. Массивы.
Допустим, мы хотим собрать статистику по каждой из граней кубика, как часто она выпадает. Для этого надо написать что-то вроде следующего кода:
var i,g,d1,d2,d3,d4,d5,d6: Integer;
В этом коде очевиден недостаток. Для анализа работы шестигранного кубика мы используем шесть переменных. В результате многие участки исходного текста нашей программы выглядят весьма похожими друг на друга - и обработка вариантов в условном операторе, и, когда понадобится показывать их содержимое - команды присваивания результатов по каждой грани полям вывода. Видно, что многие части этих команд многократно повторяются. Фактически в них изменяются лишь номера переменных и номера граней, а весь остальной код совпадает. Ряд подобных проблем мы уже научились решать с помощью оператора цикла, избавившись от необходимости многократной записи. Было бы очень здорово подобным единообразным способом хранить и обрабатывать в программе большие наборы данных одного и того же типа. Сделать это несложно. В дополнение к изученным нами операторам цикла, присваивания и разветвления по условию в любом массово известном языке программирования существует понятие массива. Массив представляет собой переменную некоторого типа, в которой хранится не одно, а несколько значений такого типа. Подобный способ организации хранения набора одинаковых по структуре элементов в одной переменной называется массивом. Все элементы располагаются в массиве последовательно, один за другим, поэтому к ним можно обращаться по их порядковому номеру. Устройство массива очень похоже на устройство оперативной памяти внутри компьютера. Память состоит из последовательности ячеек, каждая из которых имеет свой номер (называемый адресом), а каждый элемент массива (в сущности обычная ячейка памяти) имеет свой порядковый номер (относительный, по отношению к началу массива), по которому к нему можно обращаться. Но если ранее мы умышленно отошли от понятия числового адреса ячеек памяти - к наглядным буквенным идентификаторам переменных, что во многих ситуациях значительно повышает наглядность исходных текстов, то теперь мы вновь возвращаемся к числовой адресации - только на более высоком уровне абстракции и с большим уровнем комфорта. В частности, возможность обращения к элементам массива по их номеру не связана напрямую с реальными адресами этих элементов в памяти, поэтому разработчик может не заботиться об организации их местонахождения в памяти. Все эти задачи берет на себя компилятор. Для того, чтобы при описании некоторой переменной с помощью Var декларировать ее не как обычную переменную, а как массив, достаточно после записи идентификатора переменной указать набор определенных ключевых слов и задать в квадратных скобках номер первого и последнего элемента, разделенные двоеточием - в результате переменная будет считаться в программе массивом. Вот как записывается декларация массива в общем случае: var имя-переменной-массива: array [номер-первого-элемента .. номер-последнего-элемента ] of тип-данных ; Все элементы массива будут иметь один и тот же тип, который указан в этой команде. Например:
var nums: array[ 1..10 ] of Integer;
В массиве nums будет 10 элементов (10 вложенных в него переменных целочисленного типа), первый элемент будет иметь индекс (номер) 1, второй - индекс 2, десятый - индекс 10. Элемент массива, обращение к которому происходит по его индексу, называется проиндексированным . После такой записи мы можем получать доступ к значениям отдельных элементов массива nums по их порядковому номеру (индексу), а также заносить в эти элементы новые величины (как в обычные переменные). Если некоторая переменная декларирована в программе как массив, то для обращения к ее определенному элементу достаточно после имени переменной-массива указать порядковый номер этого элемента в квадратных скобках.
nums[1] := 0;
Теперь видоизменим нашу программу так, чтобы вместо шести переменных с разными именами выполнялась обработка всего одного массива, состоящего из шести элементов. Для этого перепишем место декларации так:
var i, g: Integer;
Здесь декларируется массив d, состоящий из шести элементов - целых значений, с номерами от 1 до 6. Далее все обращения к шести переменным d1-d6 в тексте программы надо изменить на обращение к одной переменной d, только следом за ее названием потребуется указывать соответствующий индекс (порядковый номер) элемента в квадратных скобках. Фактически достаточно заменить идентификатор d1 на обращение к первому элементу массива d[1], идентификатор d2 - на d[2] и так далее. Вот как теперь запишется новый вариант этого кода:
var i, g: Integer;
Из этого текста пока не ясно, в чем же преимущество использования массивов. Мы даже не можем утверждать, что повысилась наглядность программы. Ведь теперь необходимо указывать индексы в скобках, вместо того чтобы применять осмысленные буквенные идентификаторы. Но давайте вспомним такой замечательный инструмент, как оператор цикла. Именно в сочетании с массивами этот оператор начинает проявлять все свои мощные способности. Сочетаем массивы с циклами В качестве индекса при обращении к элементу массива можно указывать не только число-константу, но и любое другое выражение, тип значения которого будет целым числом (Integer)! Такие вычисляемые индексы можно применять как при обращении к элементу массива для считывания его значения, так и для записи в него новой величины. В последнем случае проиндексированный элемент массива может указываться в левой части оператора присваивания. Сначала продемонстрируем эти возможности, заменив с помощью оператора цикла шесть операторов присваивания, задающих начальные, нулевые значения элементам массива. Вот как это может выглядеть:
for i := 1 to 6 do
Запись стала значительно короче и нагляднее. Из заголовка цикла видно, что переменная i будет последовательно принимать значения от 1 до 6. В теле цикла будет выполняться задание нулевого значения элементу массива с индексом, записанным в переменной-счетчике i. В результате ноль последовательно будет присвоен элементу d[1], затем элементу d[2] и так далее, включая последний элемент d[6]. Но, пожалуй, самым главным достоинством такой записи можно считать ее независимость от количества элементов в массиве. Если в старом варианте нашей тестовой программы мы захотели бы собирать статистику не для шестигранного кубика, а для двадцатигранного, то нам бы пришлось добавить еще четырнадцать новых операторов присваивания. А в данном случае достаточно всего лишь изменить значение 6 в заголовке цикла на новое желаемое количество элементов в массиве. Модификация условного оператора - точнее, его замена на оператор цикла и использование массива - будет выглядеть еще красивее. Весь громоздкий условный оператор выбора мы теперь можем переписать с помощью всего двух операторов присваивания. В этом нам поможет переменная g, которую мы задействуем как индекс того элемента массива, в котором будет учитываться выпадание соответствующей грани кубика. Так, если выпала грань 3 (после обращения к функции Dice()), нам надо будет увеличить на единицу значение элемента d[3]. В более общем случае, если выпала грань с номером, записанным в переменную g, надо будет увеличить на единицу значение элемента d[g]:
var i, g: Integer;
begin
for i := 1 to 6 do
for i := 1 to 1000 do
Заметно, как сократился объем исходного текста программы и увеличилась его наглядность! Вот как можно занести в каждый элемент массива число, соответствующее его номеру:
for n := 1 to 6 do
Вот так - найти сумму всех элементов массива:
sum := 0;
Вот так - заполнить массив случайными значениями от 0 до 99:
for n := 1 to 6 do
Вместо 6, конечно, можно подставить любое другое значение, в зависимости от того, как вы массив описали, сколько в нем элементов. Массивы особенно полезны, когда надо обработать большие наборы однотипных данных, из сотен и тысяч элементов, обычными переменными не обойтись при этом. Основное ограничение массивов - что длина массива в Дельфи должна быть определена до начала работы программы, то есть при описании массива в разделе Var в качестве номера первого (почти всегда берется единица) и последнего элементов могут быть только числа, не переменные.
Задание N 22. Задание N 23. Очень сложное на сортировку - придумайте алгоритм сортировки значений массива :) (по убыванию или возрастанию, без разницы). ИХ множество, но попробуйте сами, не заглядывая в готовые. Строки - это массивы Строки - это на самом деле массивы, только не фиксированной длины, а переменной. То есть вы можете после определения строки var s: String; записать в нее строку
s := 'abcde' ;
и затем обратиться к 3-му элементу: writeln( s[3] ); // выведется символ "c" или заменить один символ на другой:
s[5] := 'f' ; // в s будет в результате храниться строка "abcdf"
Длину строки можно узнать функцией length(): length(s) = 5 Задание N 24. Тоже сложное. Подсчитайте, проанализировав строку, сколько в ней раз встречается каждая из 33 букв (считать только маленькие, незаглавные). Преобразовать строку в нижний регистр (все маленькие) можно функцией AnsiLowerCase: s := AnsiLowerCase(s); Входной параметр - исходная строка, возвращает функция преобразованное значение. Цифры и знаки препинания не меняются :) Подсказка. Надо завести массив из 33 элементов-счетчиков, а каждую букву строки как-то перевести в индекс. Считается, что коды букв от а до я следуют друг за другом последовательно. Как перевести символ в код? Функция ord(один-символ) возвращает числовое значение символа, а функция chr(число) возвращает символ, соответствующий числу. То есть
chr( ord( ' a ' ) ) даст ' a ' , и ord ( chr( 13 ) ) даст 13. Тогда относительный индекс некоторой буквы в алфавите (относительно русской буквы а) может быть примерно так рассчитан:
ord( буква )-ord( 'а' )+1. Единицу прибавили, чтобы номер буквы а был не нулем, а единицей. Этот индекс может быть задействован в качестве индекса массива счетчиков. Только предварительно надо проверить, чтобы индекс соответствовал маленькой русской букве, а не другим символам - ведь в исходной строке может быть что-угодно. Задание N 25. Шифрование. Старый метод шифрования текстов заключался в том, что код буквы смещался на некоторое число, и на выходе получалась абракадабра. А чтобы расшировать, надо просто было знать величину смещения. Напишите функции шифрования и расшифрования строки-параметра, сдвигая значения символов на указанный второй параметр (число). То есть если смещение - 4, а код буквы а - 128, то он преобразовывается в 132, и выдается буква с кодом 132. А расшифровка - из буквы с кодом например 132 вычитается смещение 4, и получается исходное 128 (а). Главное, чтобы противник не узнал ключ - число 4 :) Имейте в виду, что диапазон значений символов - от 0 до 255, видимый алфавит русский - по-моему, коды символов после 127 начинаются, поэтому сильно сдвигать нельзя, чтобы не появились невидимые символы, или вообще выход за границы допустимых значений. На пятерочку там... Поэкспериментируйте. В Бейсике так массив записывается, совсем просто: Dim D(6) As Integer Просто число элементов, и все. Обращение - тоже с индексом в круглых скобках, D(4) = 50 Только считается, что номер первого элемента - с НУЛЯ всегда начинается. Это в VB.NET, правда, в старых версиях может и по другому быть. То есть, если указано в описании D(6), то значит, что номер первого элемента массива - 0 ( обращение - D(0) ), второго - 1 итд.
Dim i, n As Integer, D(6) As Integer
For i = 0 to 5
А вот как со строками быть, как их индексировать, и коды символов анализировать, не знаю. Может, кто подскажет? Си. В Си массив, как в Бейсике, с нуля всегда индексируется, и декларируется схоже, только размер в квадратных скобках задается - просто после имени переменной: int d[6]; Индексация в Си всегда с нуля! Это важно. Часто путаются, кто переходит на Си с Паскаля. То есть после объявления int d[6]; к d можно обращаться с индексами от 0 до 5.
int d[6];
for( i=0; i < 6; i++ )
Строк как таковых в классическом Си нету, а есть тип данных char (одиночный символ). ИЗ них можно составлять массивы символов, строки, однако они, в отличие от других языков, будут фиксированной длины. char s[80]; // строка из 80 символов
s[0] = 'й' ; // в Си для обозначения одиночных символов, тип char, применяются одиночные кавычки, а вот для строк, хотя типа такого нету, двойные. При этом понятие строки все же существует, строкой считается последовательность символов, завершающаяся символом с кодом ноль. То есть если записать:
char s[80];
то в массив символов s запишется три символа '1', '2', '3', а следом за ними - символ с кодом 0. И хотя он невидим, для него тоже надо отводить место! То есть в записи
char s[4];
Для переменной s выделено четыре места в памяти для данных типа char, и так и выйдет при записи строки "123" - три символа и нулевой в конце. Поэтому запись
char s[3];
неверна, ноль запишется скорее всего, но непонятно куда, и может программа вылететь с ошибкой. Такие ошибки, вообще для Си характерны, в Паскале они выявляются, а в Си нет. Длина строки (число символов до нулевого) выдается функцией strlen(): s = "123"; strlen(s) даст 3. Можно так длину строки найти:
for( i =0; s[i]; i++ ) ;
После выполнения этого оператора в переменной i будет длина строки s. Такие записи только в Си возможны! Каждый символ можно трактовать как целое число (его код), и прямо указывать: s[2] = 128; Более того, отдельные символы типа 'у' (в одинарных кавычках, символы, char-s, не строки!) трактуются как целые числа, поэтому можно и так записывать:
s[2] = 128 + 'у' ; Поэтому высокопроизводительные программы, то же шифрование, обычно на Си пишутся - язык сложный, но мощный. Меньше ограничений - больше гибкости, но и больше риска сделать ошибку. В принципе, массивы - это последнее из фундаментальных понятий программирования. Типы данных/присваивание, условный оператор, оператор цикла, подпрограммы, массивы. Это абсолютная основа. Останется нам подобраться к понятию объектов и сложных типов данных, но это уже вещи не такие обязательные на самом деле. Поэтому будем постепенно делать больший уклон на практическую алгоритмизацию, способы построения программ разной сложности из этих базовых вещей. Ну и визуальное программирование параллельно, средства создания хорошего и красивого GUI. И задачки занимательные :) Что касается ваших отчетов. Публиковать оперативно постараюсь ваши лучшие отчеты (по одному на каждое решение), а другие массовые ответы худшего качества будут выставляться постепенно. Каждый, приславший лучший (на мой субъективный вкус :) отчет по любому из заданий, получает право бесплатных занятий на одном из платных курсов. (c) 2004 Сергей Бобровский bobrovsky@russianenterprisesolutions.com
Школа программирования с нуля
Все предыдущие выпуски базового курса тут:
|
http://subscribe.ru/
http://subscribe.ru/feedback/ |
Подписан адрес: Код этой рассылки: comp.soft.prog.prognull |
Отписаться |
В избранное | ||