|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Тема 4. Массивы. Разработка программ с использованием одномерных и двумерных массивовМассивы представляют собой структуры данных, состоящие из логически связанных элементов данных одного и того же типа. Массивы являются «статическими» объектами в том смысле, что их размер остается одним и тем же в процессе выполнения программы. Объявление массивов. Массив является группой ячеек памяти, логически связанных в том отношении, что все они имеют одно и то же имя и один и тот же тип. Для обращения к элементу массива необходимо указать имя массива и номер позиции этого элемента в массиве. Первый элемент в любом массиве имеет нулевой порядковый номер. Номер позиции элемента, содержащейся внутри квадратных скобок ([]), более формально называют индексом. Индекс должен быть целым числом или целочисленным выражением. Скобки, в которые заключается индекс массива, на самом деле рассматриваются в качестве операции языка Си, они имеют тот же самый приоритет, что и круглые скобки. При объявлении массива необходимо указать имя массива, тип каждого элемента и число элементов массива. При помощи одного объявления можно зарезервировать память для нескольких массивов, например: int b[100], x[27]; В программе, приведенной ниже, используется структура повторения for для инициализации нулями элементов целочисленного массива n из десяти элементов. /* Инициализация массива */ #include <stdio.h> main() { int n[10], i; for (i=0; i<=9; i++) n[i]=0; /* инициализация массива */ for (i=0; i<=9; i++) /* вывод элементов массива */ printf(“%3d%10d\n”, i, n[i]); return 0; } Результат программы: 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 Элементы массива также могут инициализироваться при объявлении массива путем помещения вслед за его объявлением знака равенства и списка (заключенного в фигурные скобки) инициализирующих значений, разделенных запятыми. Программа, приведенная ниже, инициализирует целочисленный массив десятью значениями. /* Инициализация массива при объявлении */ #include <stdio.h> main() { int i, n[10]={2, 27, 64, 18, 95, 14, 90, 70, 6, 3}; for (i=0; i<=9; i++) printf(“%3d”, n[i]); return 0; } Результат программы: 2 27 64 18 95 14 90 70 6 3 Если инициализирующих значений меньше, чем элементов массива, остающиеся элементы автоматически инициализируются нулями. Например, элементы массива nможно было бы инициализировать нулями посредством объявления int n[10]={0}; Которое явно инициализирует нулем первый элемент и автоматически инициализирует нулями оставшиеся девять элементов, поскольку инициализирующих значений меньше, чем элементов в массиве. Необходимо помнить, что массивы не инициализируются нулями автоматически. Программист должен инициализировать по крайней мере первый элемент, чтобы оставшиеся элементы были автоматически заполнены нулями. Если размер массива не включается в его объявление со списком инициализирующих значений, то число элементов в массиве будет равно числу элементов в списке инициализации. Массивы в Си могут иметь несколько индексов. Многомерные массивы часто применяются для предоставления таблиц, состоящих из значений, упорядоченных по строкам и столбцам. Для идентификации конкретного элемента таблицы мы должны указать два индекса: первый, идентифицирующий строку элемента, и второй, идентифицирующий столбец. Такие таблицы или массивы называются двумерными массивами. Многомерный массив, подобно одномерному, может быть инициализирован при его объявлении. Например, двумерный массив b[2][2] может быть объявлен и инициализирован посредством int b[2][2]={{1, 2}, {3, 4}}; Значения группируются в фигурных скобках по строкам. Таким образом, 1 и 2 инициализируют b[0][0] и b[0][1], 3 и 4 инициализируют b[1][0] и b[1][1]. Если для данной строки недостаточно инициализирующих значений, оставшиеся ее элементы инициализируются нулями. Таким образом, объявление int b[2][2]={{1}, {3, 4}}; инициализировало бы b[0][0] единицей, b[0][1] нулем, b[1][0] тройкой и b[1][1] четверкой. Следующая программа демонстрирует инициализацию двумерных массивов при их объявлении. В программе объявляются три массива с двумя строками и тремя столбцами (каждый состоит из шести элементов). Объявление массива а1 предусматривает шесть инициализирующих значений в двух подсписках. Первый подсписок инициализирует первую строку массива значениями 1, 2 и 3; второй подсписок инициализирует вторую строку массива значениями 4, 5 и 6. Если из списка инициализирующих значений массива а1 убрать фигурные скобки, в которые заключен каждый подсписок, компилятор автоматически проинициализирует элементы первой строки, а затем элементы второй строки. Объявление массива а2 предусматривает пять инициализирующих значений. Инициализирующие значения присваиваются сначала первой строке, затем второй строке. Элемент а2[1][2] инициализирован нулем. Объявление массива а3 предусматривает три инициализирующих значения в двух подсписках. Соответственно элементы а3[0][2], а3[1][1] и а3[1][2] инициализируются нулями. Для вывода элементов каждого массива в программе вызывается функция printarray. /* Инициализация многомерного массива */ #include <stdio.h> void printarray(int [][3]); main() { int a1[2][3] = {{1, 2, 3}, {4, 5, 6}}, a2[2][3] = {1, 2, 3, 4, 5}, a3[2][3] = {{1, 2}, {4}}, printf(“Массив А1”); printfarray(a1); printf(“Массив А2”); printfarray(a2); printf(“Массив А3”); printfarray(a3); printf(“\n”); return 0; } void printarray(int a[][3]); { int i, j; for (i=0; i<=1; i++) { for (j=0; j<=2; j++) printf(“%d ”, a[i][j]); printf(“\n”); } } Результат программы: Массив А1 1 2 3 4 5 6 Массив А2 1 2 3 4 5 0 Массив А3 1 2 0 4 0 0
Основная литература: 1осн[223-253], 2осн[244-255] Дополнительная литература: 5доп[41-46], 7доп[15-23] Контрольные вопросы: 1. Как осуществляется ввод и вывод одномерного массива? 2. Как осуществляется ввод и вывод двумерного массива? 3. При каком условии можно передать все элементы одного массива другому массиву? 4. Каким образом можно сравнить два массива? 5. Приведите примеры инициализации одномерных и двумерных массивов. Тема 5. Функции в Си. Создание и использование функций. В языке Си все программы рассматриваются как функции. Обычно программы на этом языке состоят из большого числа небольших функций. Для каждой из используемых функций приводится описание и определение функции (Описание функции дает информацию о типе функции и о порядке следования параметров. При определении функции указываются конкретные операторы, которые необходимо выполнить). Функции должны иметь тот же тип, что и значения, которые они возвращают в качестве результатов. По умолчанию предполагается, что функции имеют тип int. Если функция имеет другой тип, он должен быть указан и в вызывающей программе, и в самом определении функции. Рассмотрим описание функций: можно использовать два различных стиля описания функций (классический и современный стиль). В первом случае формат описания функции следующий: тип имя_функции (); Эта спецификация описывает имя функции и тип возвращаемого значения. Современный стиль используется в конструкциях расширенной версии Си, предложенной ANSI. При описании функций в этой версии Си используются специальные средства языка, известные под названием «прототип функции». Описание функции с использованием ее прототипа содержит дополнительно информацию о ее параметрах: тип имя_функции (пар_инф1, пар_инф2, …); где параметр пар_инфi – информация о имени и типе формальных параметров. Определение функции. Так же, как и в описании функции, при определении функций можно использовать два стиля – классический и современный. Классический формат определения функций имеет следующий вид: тип имя_функции (имена параметров) определение параметров; { локальные описания; операторы; } Формат описания в современном стиле предусматривает определение параметров функции в скобках, следующих за именем функции: тип имя_функции (пар_инф, пар_инф, …) где определение параметра пар_инф – содержит информацию о передаваемом параметре: тип и идентификатор. Необходимо отметить, что ряд описаний (константы, типы данных, переменные), содержащихся внутри функции (исключение составляет главная функция main0), определены только внутри этой функции. Поэтому язык Си не поддерживает вложенность функций, т.е. одна функция не может быть объявлена внутри другой функции. Функции могут быть размещены в программе в различном порядке и считаются глобальными для всей программы, включая встроенные функции, описанные до их использования. Вызов функции осуществляется по имени функции, в скобках указываются фактические аргументы. Результат выполнения функции возвращается при помощи оператора return. Общий вид: Return (выражение); Оператор завершает выполнение функции и передает управление следующему оператору в вызывающей функции. Это происходит даже в том случае, если оператор return является не последним оператором тела функции. Можно использовать оператор return в виде: return; return 0; Его применение приводит к тому, что функция в которой он содержится, завершает свое выполнение управление (передается) возвращается в вызывающую функцию. Поскольку у данного оператора отсутствует выражение в скобках, никакое значение при этом не передается функции. main() { float y, x, mult(); /* описание в вызывающей программе */ int n; ……… y=mult(x, n); ………} float mult(v, k) /* описание в определении функции */ float v; int k; { float res; for (res=0.0; k>0; k--) res=res*v; return (res); } /* возвращает значение типа float */ С помощью оператора return в вызывающую программу можно передать только одну величину. Если нужно передать две величины, нужно воспользоваться указателями. Определение функции специфицирует имя, формальные параметры и тело функции. Оно может также специфицировать тип возвращаемого значения и класс памяти функции. Синтаксис определения функции следующий: [<спецификация КП>][<спецификация типа>]<описатель>([<список параметров>]) [<объявление параметров>] <тело функции> Спецификация класса памяти <спец. КП> задает класс памяти функции. <спец. типа> в совокупности с описателем определяет тип возвращаемого значения и имя функции. <Список параметров> представляет собой список (возможно, пустой) имен формальных параметров, значения которых передаются функции при вызове. <Объявления параметров> задают идентификаторы и типы формальных параметров. <Тело функции> - составной оператор, содержащий объявления локальных переменных и операторы. Современная конструкция: [<спецификация КП>][<спецификация типа>]<описатель>([<список объявлений параметров>])<тело функции> Объявление функции: классическая форма: [<спецификация КП>][<спецификация типа>]<описатель>([<список типов аргументов>]); Объявление функции специфицирует имя функции, тип возвращаемого значения и, возможно, типы ее аргументов и их число. Современный стиль описания (объявление прототипов). В списке типов аргументов прототип может содержать также и идентификаторы этих аргументов. float f1(float a, float b) { float c; c=(2*pow(a,3)+sin a)/pow(a+b,4); return c; } main() { float x,y,s=0; clrscr (); printf (“\n Введите x, y”); scanf (“%f %f ”, &x, &y); s=f1(5.6, y)+f1(2*x-1, x*y); printf(“\n s=%6.2f ”,s); return 0; } Адресные операции. Си поддерживает две специальные адресные операции: операцию определения адреса (&) и операцию обращения по адресу (*). Операция & возвращает адрес данной переменной. Если sum является переменной типа int, то &sum является адресом этой переменной. Указатели. Указатель является переменной, которая содержит адрес некоторых данных. Вообще говоря, указатель – это некоторое символическое представление адреса. &sum в данном случае означает «указатель на переменную sum». Фактическим адресом является число, а символическое представление адреса &sum является константой типа указатель. Т.обр. адрес ячейки памяти, отводимой переменной sum в процессе выполнения программы не меняется. В языке Си имеются и переменные типа указатель. Значением переменной типа указатель служит адрес некоторой величины. Пусть указатель обозначен идентификатором ptr, тогда оператор следующего вида присваивает адрес sum переменной ptr: ptr=&sum. В этом случае говорят, что ptr «указывает на» sum. Итак, ptr – переменная, &sum – константа. Переменная ptr может указывать на какой-нибудь другой объект: ptr=&max Значением ptr является адрес переменной max. Рассмотрим операцию обращения по адресу (*) или операцию косвенной адресации. предположим в переменной ptr соержится ссылка на переменную max. Тогда для доступа к значению этой переменной можно воспользоваться операцией обращения по адресу (*). Для определения значения, на которое указывает ptr запишем следующий оператор: Res=*ptr; (Последние два оператора, взятые вместе, эквивалентны следующему: Res=max;) Использование операции получения адреса и косвенной адресации оказывается далеко не прямым путем к результату, отсюда и появление слова «косвенная» в названии операции.). Операция (*) – когда за этим знаком следует указатель на переменную, результатом операции является величина, помещенная в ячейку с указанным адресом. Описание указателей. При описании переменных типа «указатель» необходимо указать на переменную какого типа ссылается данный указатель. Т.к. переменные разных типов занимают различное число ячеек, в то время как для некоторых операций, связанных с указателями, требуется знать объем отведенной памяти. Примеры правильного описания указателей: int * iptr; char * cptr; float * fptr; Использование указателей для связи между функциями. Рассмотрим пример использования указателей для установления связи между функциями. В данном примере указатели используются для обмена значений переменных. main() { int x=5, y=10; printf (“x=%d y=%d\n”, x, y); change (&x, &y); /*передача адресов функции*/ printf (“x=%d y=%d\n”, x, y); } change (u,v) int *u, *v; /*u и v являются указателями*/ { int temp; temp=*u; /*temp присваивается значение, на которое указывает u*/ *u=*v; *v=temp; } Данная функция изменяет значения переменных x и y. Путем передачи функции адресов переменных х и у мы предоставили ей возможность доступа к ним. Используя указатели и операцию (*), функция смогла извлечь величины, помещенные в соответствующие ячейки памяти, и поменять их местами. Основная литература: 1осн[173-205], 2осн[256-290] Дополнительная литература: 5доп[51-54], 7доп[23-28] Контрольные вопросы: 1. Могут ли имена формальных и фактических параметров подпрограмм совпадать между собой? 2. В чем состоит отличие описания процедуры и функции? 3. Какие параметры называются формальными и какие – фактическими? 4. Какие существуют стили описания и определения функций? 5. Назовите оператор для возвращения результата выполнения функции?
Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.027 сек.) |