|
Модульное программирование |
тандартная запись адреса имеет форму сегмент: смещение; например, предыдущий адрес можно записать как 2F84: 0532. Отметим, что поскольку смещения могут перекрываться, данная пара сегмент: смещение не является уникальной; следующие адреса относятся к одной и той же точке памяти:0000: 01230002: 01030008: 00A30010: 00230012: 0003Сегменты могут (но не должны) перекрываться. Например, все четыре сегмента могут начинаться с одного и того же адреса, что означает, что вся ваша программа в целом займет не более 64 Кб - но тогда в пределах этой памяти должны поместиться и коды программы, и данные, и стек.2.1 Виды моделей памятиВ 16-разрядных программах вы можете использовать 6 моделей памяти: крохотную, малую, среднюю, компактную, большую и огромную.Tiny (крохотная). Эта модель памяти используется в тех случаях, когда абсолютным критерием достоинства программы является размер ее загрузочного кода. Это минимальная из моделей памяти. Все четыре сегментных регистра (CS, DS, SS и ES) устанавливаются на один и тот же адрес, что дает общий размер кода, данных и стека, равный 64К. Используются исключительно ближние указатели.Small (малая). Эта модель хорошо подходит для небольших прикладных программ. Сегменты кода и данных расположены отдельно друг от друга и не перекрываются, что позволяет иметь 64К кода программы и 64К данных и стека. Используются только указатели near.Medium (средняя). Эта модель годится для больших программ, для которых не требуется держать в памяти большой объем данных. Для кода, но не для данных используются указатели far. В результате данные плюс стек ограничены размером 64К, а код может занимать до 1М.Compact (компактная). Лучше всего использовать эту модель в тех случаях, когда размер кода невелик, но требуется адресация большого объема данных. Указатели far используются для данных, но не для кода. Следовательно, код здесь ограничен 64К, а предельный размер данных - 1 Мб.Large (большая). Модели large и huge применяются только в очень больших программах. Дальние указатели используются как для кода, так и для данных, что дает предельный размер 1 Мб для обоих.Huge (огромная). Дальние указатели используются как для кода, так и для данных. Borland C обычно ограничивает размер статических данных 64К; модель памяти huge отменяет это ограничение, позволяя статическим данным занимать более 64К.Для выбора любой из этих моделей памяти вы должны либо воспользоваться соответствующим параметром меню интегрированной среды, либо ввести параметр при запуске компилятора, работающего в режиме командной строки.2.2 Размещение исполняемого файла в ОЗУ в модели largeМодели памяти устроены по-разному. Рассмотрим расположение областей памяти в модели large.Область кода содержит машинные коды функций программы. Функции, присоединенные к exe-файлу на стадии линковки, размещаются вне области кода.Область данных содержит глобальные и статические переменные, строковые константы.В стеке размещаются локальные переменные, параметры, передаваемые функциям, и ряд других данных. Как правило, стек растет сверху вниз, занимая пульсирующую непрерывную область. В случае переполнения стека происходит его "налезание" стека на область данных и выдается соответствующее сообщение. Проверка стека увеличивает время работы программы и ее можно отключить в Options-Entry/Exit Code Generation-Stack options-Test stack overflow.В кучу данные помещаются только по указанию программиста и не имеют имени. К ним можно обратиться только по адресу, расположенному в локальной или глобальной переменной.Рис.1. Сегментация для модели памяти Large3. Передача данных в функциюСи - язык сугубо процедурный и основной логической единицей программы является функция. Формат описания функции следующий:[тип возвращаемого значения] имя_функции (список параметров){тело функции[return возвращаемое_значение] }В скобках помещена необязательная часть конструкции.В списке параметров указывают данные, которые необходимо передать в функцию. Ниже рассмотрены различные способы передачи данных в функцию.3.1 Передача параметров по значениюПараметры функции передаются по значению и могут рассматриваться как локальные переменные, для которых выделяется память при вызове функции и производится инициализация значениями фактических параметров. При выходе из функции значения этих переменных теряются. Поскольку передача параметров происходит по значению, в теле функции нельзя изменить значения переменных в вызывающей функции, являющихся фактическими параметрами.Например:void print_num (int i, int j){ printf ("значение i=%d. Значение j=%d. ", i,j);}Обращение в программе к данной функции будет таковым:print_num (6, 19);3.2 Передача параметров по адресуРассмотрим пример функции, которая меняет значение переменных местами:void change (int x, int y){ int k=x;x=y;y=k;}В данной функции значения переменных x и y, являющихся формальными параметрами, меняются местами, но поскольку эти переменные существуют только внутри функции change, значения фактических параметров, используемых при вызове функции, останутся неизменными. Для того чтобы менялись местами значения фактических аргументов можно использовать функцию приведенную в следующем примере.Пример:void change (int *x, int *y){ int k=*x;*x=*y;*y=k;}При вызове такой функции в качестве фактических параметров должны быть использованы не значения переменных, а их адреса change (&a,&b);3.3 Передача одномерных массивовПри передаче одномерного массива в функцию следует учитывать, что имя массива не содержит информации о размере этого массива. Поэтому необходимо передавать два параметра: имя массива и размер.Пример.int sum (int A [], int Dim); // прототипint sum (int A [], int Dim); // заголовок{….} // телофункцииvoid main (){int res, A [] = {2,1,3,2};res = sum (A,4);} // вызов функции sumФормальный аргумент имени массива может иметь вид int *A.int sum (int *A, int Dim); // прототипДля определения размера массива при вызове функции можно использовать выражение sizeof (A) /sizeof (int) или sizeof (A) /sizeof (A []). Например,res = sum (A, sizeof (A) /sizeof (A []));3.4 Передача двумерных массивовСпособ 1. При передаче двумерного массива в функцию следует учитывать, что количество элементов в строке массива является частью типа имени этого массива. Так например, для массива int A [3] [4] имя массива А имеет тип int (*) [4], т.е. А - это указатель на одномерный массив из 4 элементов типа int.Поэтому необходимо передавать два параметра: имя массива и количество строк в массиве.Пример.int sum2 (int A [] [4], int M); // прототипint sum2 (int A [] [4], int M); // заголовок{….} // телофункцииvoid main (){int res, A [] [4] = {{2,1,3,2}, {2,3,4,5}}; // две строки, четыре столобцаres = sum2 (A,2); // вызов функции sum2}Формальный аргумент имени массива может иметь вид int (*A) [4].int sum2 (int (*A) [4], int M); // прототипДля определения размера массива при вызове функции можно использовать выражение sizeof (A) /sizeof (A []). Например,res = sum2 (A, sizeof (A) /sizeof (A []));Способ 2. Другой способ передачи двумерного массива в функцию состоит в погружении фактического двумерного массива с размерами MxN в двумерный массив заведомо больших размеров. Пи этом достаточно взять большой размер стоки, например, 100.int sum3 (int A [] [100], int M, int N); // прототипint sum3 (int A [] [100], int M, int N); // заголовок{….} // телофункцииvoid main (){int res, A [2] [100] = {{2,1,3,2}, {2,3,4,5}}; /* две строки, четыре столбца с чатичной инициалиазацией*/res = sum3 (A, 2,4); // вызов функции sum3}Способ 3. Третий способ передачи двумерного массива в функцию состоит в эмуляции фактического двумерного массива с размерами MxN с помощью одномерного массива с размером M*N. Пи этом M*N должно быть меньше 64К.int sum4 (int A [], int M, int N); // прототипint sum4 (int A [], int M, int N); // заголовок{….} // телофункцииvoid main (){int res, A [2] [4] = {{2,1,3,2}, {2,3,4,5}}; /* две строки, четыре столбца */res = sum4 ( (int *) A, 2,4); // вызов функции sum4}4. Тестирование функцийВычислительные модули необходимо тщательно протестировать с помощью отдельной тестовой функции с прототипомvoid test (void);При тестировании следует соблюдать следующие требования:автоматизм, то есть от программиста при тестировании не требуется никаких действий,прозрачность. Это означает, что функция test выводит сообщения на экран только в случае возникновения ошибок.иллюстративность: листинг тестовой функции позволяет посмотреть различные способы вызова проверяемой функции.всесторонность, то есть при тестировании необходимо рассмотреть все крайние ситуации.В программе должны осуществляться все возможные проверки, в частности:на корректность входных данных,при выделении динамической памяти,на выход индексов массива из диапазона.5. Практические задания5.1 Указать классы памяти переменнойЧто напечатает программа? Укажите область действия, область видимости и продолжительность жизни всех переменных n.int n = 1;void main (){printf (“%d", n);static int n=3;printf (“%d", n);while (n--){printf (“%d", n);int n=10;printf (“%d", n);printf (“%d”,:: n+n);}}5.2 Работаем с адресамиУ некоторой программы в модели large при работе в отладчике регистры содержат следующие значения: CS = 1ADF, DS=1AE3, SS=1B26, SP=0FD2.Найдите размеры областей памяти.Укажите диапазоны возможных адресов для:переменной int n=2, если она а) глобальная, б) статическая, в) локальная;содержимого указателя char *str=”Hello”;значения адресной константы main;содержимого указателя int *A= (int *) malloc (1000).5.3 Прототипы функций5.3.1 СвопингНапишите прототип функции, которая организует обмен значений двух переменных.5.3.2 Индексы максимальных элементов одномерного массиваНапишите прототип функции, которая находит индексы максимальных элементов одномерного массива.5.3.3 Индексы максимальных элементов двумерного массиваНапишите прототип функции, которая находит индексы максимальных элементов двумерного массива с заданными размерами.5.3.4 Угол между двумя векторамиНапишите прототип функции, которая находит угол в радианах между двумя векторами из пространства Rn.5.3.5 Определитель матрицыНапишите прототип функции, которая находит определитель квадратной матрицы с размерами nxn.5.4 Выделение фрагмента программы в отдельную функциюРазбиение программы на функции#include <stdio. h>void main (){int a, b, div, mod;printf (“Введите два целых числа”);scanf (“%d%d”, &a, &b);div = a/b;mod = a%b;printf (“\n%d /%d =%d”, a, b, div);printf (“\n%d%%%d =%d", a, b, mod);}Выделите в три отдельных функции фрагменты, связанные с вводом данных, с вычислениями и с организацией вывода результатов. Вычислительная функция должна быть одна. Глобальные переменные не использовать.5.5 Тестирование функции5.5.1 Сортировка массиваСледующий прототип функции сортирует массив А размером n по возрастанию на месте оригинального массива void sort (int A [], int n);Напишите тест этой функции для трех различных вариантов исходных данных.5.5.2 МиниМаксФункция находит минимальное и максимальное из двух чисел типа int и имеет прототипvoid MinMax (int a, int b, int *pmin, int *pmax);Напишите тест для этой функции.6. Лабораторные задания6.1 Линейное уравнениеНаписать функцию, которая решает линейное уравнение a • x + b = 0 с проверкой выхода за диапазон типа float. Прототип функцииint linur (float a, float b, float *px);Функция получает: a и b - коэффициенты уравнения, px - указатель на ячейку, в которую будет помещен единственный корень уравнения.Функция возвращает:0 - нет решения,1 - найдено единственное решение,2 - любое число является решением,3 - решение единственное, но не входит в диапазон типа переменной x.Вывод текстовой информации с результатами решения организовать с использованием оператора switch. Выход из программы должен быть единственным. Организовать тестирование функции linur.6.2 Четные элементы массиваНапишите функцию, которая находит все четные элементы одномерного массива элементов типа int. Организовать тестирование функции.Прототип функции int Chot (int A [], int DimA, int FoundA []);6.3 Нахождение простых чиселНапишите функцию, которая находит все простые числа и их количество до long N включительно. Натуральное число m > 1 называется простым, если оно делится только на 1 и на само себя. Организовать тестирование функции.Прототип функции.long AllProst (long N, long Prost [], int DimProst, int *flag);6.4 Количество вхождений подстроки в строкуНапишите функцию, которая определяет количество вхождений подстроки в строку. Организовать тестирование функции.Прототип функцииint NumStrStr (char *str, char *substr);6.5 Произведение матрицНапишите функцию, которая находит произведение двух прямоугольных матриц с согласованными размерами. Организовать тестирование функции.Прототип функцииvoid MMult (float A [], float B [], float AB [], int m, int n, int k);Здесь одномерные массивы эмулируют двумерные массивы.7. Дополнительные заданияНаписать функцию принадлежности точки невыпуклому многоугольнику без самопересечений.Написать функции tolowerrus и toupperrus для перевода одной русской буквы из верхнего регистра в нижний и наоборот.Библиографический список 1. Керниган Б. Язык программирования Си / Б. Керниган, Д. Ритчи. СПб.: Невский диалект, 2001.352 с. 2. Подбельский В.В. Программирование на языке Си / В.В. Подбельский, С.С. Фомин. М.: Финансы и статистика, 2004.600 с. 3. Программирование в Си. Организация ввода-вывода: метод. указания / сост. С.П. Трофимов. Екатеринбург: УГТУ, 1998.14 с. 4. Программирование в Си. Динамическое распределение памяти: метод. указания / сост. С.П. Трофимов. Екатеринбург: УГТУ, 1998.13 с.
Страницы: 1, 2
|
|
|
© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент. |
|
|