Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си (1114934), страница 3
Текст из файла (страница 3)
int c,k;switch(c=getchar()) {case ‘0’:case ‘1’:case ‘2’:case ‘3’:case ‘4’:case ‘5’:case ‘6’:case ‘7’:case ‘8’:case ‘9’: k=0; break;case ‘a’: k=1; break;default: k=2;}Операторы цикла while и do-whileВ операторе цикла с предусловием:while (<выражение>) <оператор>и операторе цикла с постусловием:do <оператор> while(<выражение>);14тело цикла выполняется до тех пор, пока выражение истинно. Если вцикле необходимо выполнить несколько операторов, используетсясоставной оператор {}.Задача 2.
Из стандартного входного потока ввести строку и записатьее в массив str. Длина строки не превышает 80 символов.... int c,i;char str[80];i=0;while((c=getchar())!=’\n’) str[i++]=c;str[i]=’\0’;Оператор цикла forОператор цикла for состоит из заголовка и тела цикла.for([<выражение1>];[<выражение2>];[<выражение3>])<оператор>Оператор тела цикла выполняется до тех пор, покавыражение2 истинно. При отсутствии выражение2 считается истинным. Выражение1 обычно содержит начальные присваивания, авыражение3 – изменение значения параметра цикла на каждой итерации. В этих выражениях часто используют операцию "," (запятая). Алгоритм выполнения цикла for выглядит следующим образом:< выражение1>;while(<выражение2>) { <оператор> <выражение3>; }Например, чтобы обнулить элементы целочисленного массива,можно использовать цикл for....int m[10], i;for(i=0;i<10;i++) m[i]=0;В вырожденном случае все выражения и оператор тела цикла могутотсутствовать.
Например: for(;;); - это бесконечный цикл.Включение в заголовок цикла посторонних вычислений допустимо, но считается плохим стилем программирования....int m[10], i;for(i=0;i<10;m[i++]=0);Примечание. Параметр цикла и составляющие условия его окончания могут изменяться в теле цикла. Выходное значение параметрацикла всегда определено.Задача 3. Определить длину строки. Нулевой байт не считать....char s[100];int len, i;for(i=0;s[i];i++);len=i;Задача 4.
Удалить из строки все пробелы....char s[100];15int i, j;for(i=0,j=0;s[i];i++)if(s[i]!=’ ‘) s[j++]=s[i];s[j]=’\0’;Задача 5. Нарисовать горизонтальную гистограмму частоты вхождения введенных символов. Ввести масштабирование по горизонтальной оси так, чтобы гистограмма была развернута на все окно.#include <stdio.h>main(){ int c, m[256]={0}, i, j, max;while((c=getchar())!=’\n’) m[c]++;for(i=1,max=m[0];i<256;i++)if(max<m[i]) max=m[i];for(i=0;i<256;i++)if(m[i]){printf(“%c”,i);for(j=0;j<80*m[i]/max;j++) putchar(‘*’);putchar(‘\n’);}}Операторы break и continueОператор break; вызывает немедленный выход из тела циклаили из переключателя switch.Оператор continue; вызывает немедленный переход к следующей итерации цикла (while, do-while или for).Упражнения1.
#define MAXLEN 256char str[MAXLEN];int i;Пусть в символьный массив str записана строка, длина которойменьше MAXLEN.a) Реверсировать строку, не используя дополнительных массивов.b) char str1[MAXLEN];Копировать строку str в str1.c) Преобразовать строку в целое.d) Целое число, записанное в переменной i, преобразовать встроку.2. Входной поток состоит из слов. Длина слова не превышает 80символов. Разделители между словами: пробел, запятая, конецстроки.a) Распечатать входной поток по одному слову в строке.b) Распечатать размер самой длинной строки.163.4.5.6.c) Распечатать самую длинную строку.Построить вертикальную гистограмму частоты вхождения произвольных символов во вводимую из стандартного входного потока строку. Гистограмма должна занимать все окно, т.е.
масштабирование должно быть произведено как по вертикали, так и погоризонтали.Ввести строку из стандартного входного потока в массив типаchar, удалить из строки комментарии. (/* . . . */) Дополнительныемассивы не использовать.Написать машинно-независимую программу, обнуляющую каждую четную двоичную единицу в числе типа int.Написать машинно-независимую программу, транспонирующуюдвоичный код целого.17ТЕМА 3. Понятие функции. Общая структура программы. Области видимости и существования переменныхПонятие функцииКак уже говорилось, программа на языке Си представляет собой набор функций.
Для того, чтобы программа была выполняемой,она должна содержать функцию с названием main, которой передается управление при запуске программы на выполнение.В Си отсутствует понятие вложенных функций, все функциинаходятся на одном уровне видимости (глобальном), и их именадолжны быть уникальны в рамках программы.В стандарте ANSI C представлено два способа описания и определения функций, так называемые «новая» (введенная стандартом) и «старая» (используемая до принятия стандарта) нотации.Согласно новой нотации определение любой функции имеет следующий вид:[<тип результата>]<имя функции>([список параметров]){ [декларации][операторы]}Согласно старой нотации функция определяется следующим образом:[<тип результата>]<имя функции>([список имен парам.])[описание параметров]{ [декларации][операторы]}В этом случае в круглых скобках после имени функции перечисляются имена параметров, а их типы задаются перед первой открывающей фигурной скобкой.Отметим, что запись параметров в старой нотации можновстретить лишь в очень старых кусках кода на языке Си, написанных до введения первой версии стандарта ANSI C 1989 года.
Компиляторы (и стандарт) допускают такую форму записи лишь из соображений обратной совместимости со старым кодом. Ни при какихобстоятельствах программисту не следует использовать старую нотацию при создании новых программ на языке Си.Возвращаемое значениеФункция может возвращать одно значение, тип которого указывается в заголовке, а само значение задается выражением в операторе return:return <выражение>;18Оператор return возвращает управление вызвавшей функции. Выполнение оператора return в функции main вызовет завершениепрограммы.Если возвращаемое значение имеет тип int, то тип результата приописании функции можно не указывать (хотя это и не является хорошим стилем программирования).В языке Си нет разделения на процедуры и функции.
Функция может не возвращать значение, тогда вместо типа результата при описании функции следует писать void, а оператор returnиспользуется без возвращаемого значения:void f(int a) {/*…*/return;}Попытка использовать оператор return с параметром в функции, не возвращающей значения (и наоборот) приведет к ошибкекомпиляции.Прототипы функцийВ стандарт Си было добавлено средство контроля за соответствием фактических параметров в вызове функции ее формальнымпараметрам.
Если вызов функции расположен в теле программы доее определения, то до использования такой функции (обычно в начале программного файла или в подключаемом заголовочном файле)задается ее описание, или прототип. Синтаксически прототип повторяет заголовок функции, за которым вместо ее тела следует точкас запятой.При отсутствии прототипа функции, если в выражении встретилось имя, нигде ранее не описанное, за которым следует открывающая скобка, компилятор будет считать его именем функции, возвращающей значение типа int, не делая никаких предположений оее параметрах. Это означает, что при несоответствии типов формальных и фактических параметров автоматическое приведение типов не осуществляется, что может привести к ошибочному результату.
А при наличии прототипа функции все приведения типов осуществляются автоматически.Согласованность имен параметров в прототипе и в определении функции не требуется, более того, в прототипе могут быть указаны только типы параметров без имен.Если функция не принимает никаких параметров, в круглыхскобках после ее имени следует указать ключевое слово void. «Пустой» список параметров в прототипе функции не говорит компилятору о том, что их нет – в последнем случае компилятор просто не19делает никаких предположений о количестве и типах параметровфункции (как и в случае отсутствия прототипа).В случае старой нотации в прототипе функции параметры неуказываются, и компилятор не может обнаружить ошибок при несоответствии количества формальных и фактических параметров илиих типов. Пример описания и определения функции в новой и в старой нотациях:/*прототип */int f(char);.../* определение */int f(char c){/*…тело функции…*/}/*прототип */int f();.../* определение */int f(c)char c;{/*…тело функции…*/}новая нотациястарая нотацияВ языке Си аргументы всегда передаются в функцию «по значению».
То же касается и возврата значения из функции.Задача 1. Написать функцию, суммирующую два вещественныхзначения в двух вариантах: сумма – возвращаемое значение функциии сумма – параметр функции.. . .double sum1(double,double);/* прототипфункции sum1*/void sum2(double,double,double*); /* прототипфункции sum2*/main(){ double a1=2.5, u;int a2=3;u=sum1(a1,a2);printf(“u=%f\n”,u); /* u=5.5 */sum2(a1,a2,&u);printf(“u=%f\n”,u); /* u=5.5 */}double sum1(double x,double y){ return x+y; }void sum2(double x,double y,double *z){ *z=x+y; }Список параметров переменной длиныСписок формальных параметров функции может быть переменной длины – в этом случае он заканчивается “, …” и должен со20держать хотя бы один обычный именованный параметр. Примеромтакой функции является функция печати printf, описанная в заголовочном файле <stdio.h>:int printf(const char *format, …);Для работы с параметрами, количество и тип которых заранеене известны, используется механизм макросов из файла стандартнойбиблиотеки <stdarg.h>.
В теле функции должна быть описана переменная типа va_list, которая будет содержать информацию осписке неименованных аргументов. Чтобы получить доступ к неименованным параметрам через эту переменную, необходимо прежде всего обратиться к макросу va_start. Макрос va_startполучает два параметра: упомянутую переменную типа va_list ипоследний именованный параметр функции.
Он инициализирует переменную типа va_list так, чтобы она указывала на первый неименованный параметр:int f(p1, p2, ...){va_list parg;va_start(parg, p2);/* p2 – последнийименованный параметр функции f */int i = va_arg(parg, int);...va_end(parg);}Далее, каждое обращение к макросу va_arg выдает очереднойпараметр и передвигает указатель (переменную типа va_list) наследующий параметр.
Макросу va_arg передают два аргумента: переменную типа va_list, предварительно проинициализированнуюс помощью va_start, и имя типа ожидаемого параметра. Таким об-разом, программа сама должна определить, каков тип очередногоожидаемого ею аргумента из неименованного списка. Макросva_end нужен для корректного завершения работы с переменнойтипа va_list.Поскольку функции не известны ни типы передаваемых неименованных параметров, ни их количество, то для корректной работы с такими параметрами может использоваться различная дополнительная информация. Например, как в случае функции printf,параметр format полностью определяет типы и число последующихпараметров.