Н.В. Вдовикина, И.В. Машечкин, А.Н. Терехин, В.В. Тюляева - Программирование в ОС UNIX на языке Си (1114934), страница 6
Текст из файла (страница 6)
Каждая переменная – это строка видаимя_переменной=значение_переменнойУпражнения91. Написать функцию конкатенации строк (аналог функции strcat).2. Написать функцию сравнения строк (аналог функции strcmp).3. Присвоить переменной единицу, если одна строка содержится вконце другой, и ноль в противном случае.4. Поменять местами первый отрицательный элемент вещественного массива m1 с последним положительным элементом вещественного массива m2.5. Изменить знак у всех отрицательных элементов вещественногомассива X.6.
Определить, у скольких элементов целочисленного массива Xравные соседи(предыдущий и последующий элементы). Записатьответ в переменную n.7. Написать функцию проверки на равенство строк s1 и s2 при условии, что пробелы не учитываются.8. Написать аналог функции strstr , которая возвращает указатель напервое вхождение одной строки в другую и нулевой указатель впротивном случае. Используя функцию strstr, найти последнеевхождение строки “end” во введенной строке. Распечатать символы, которые следуют за этим вхождением.9. Функции передаются 2 Си-строки:char s[], t[];Все цифры строки s записать в начало строки t, а остальные символы – в конец (в любом порядке).10.Дано множество точек на плоскости, заданных координатами(x,y). Написать функцию, возвращающую минимальное расстояние между двумя точками.11.Написать функцию обработки вещественной матрицы (50x20).Функция должна находить строку, содержащую наибольшее количество отрицательных элементов и распечатывать все элементы этой строки.
Если таких строк несколько, то печатать все такие строки.12.Написать функцию, осуществляющую умножение двух матрицпорядка MxN и NxK.Задачи №13 и №14 взяты из первого издания книги Б.Керниган, Д.Ритчи «Язык программирования Си»93613.Что будет выведено на печать?int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};int *pa[3]={a[0],a[1],a[2]};int *p=a[0];main(){ int i;for(i=0;i<3;i++)printf(“%d %d %d %d %d\n”,a[i][2i],*a[i],*(*(a+i)+i),*pa[i],p[i]);}14.Что будет выведено на печать?char *c[]={“ENTER”,”NEW”,”POINT”,”FIRST”};char **cp[]={c+3,c+2,c+1,c};char ***cpp=cp;main(){ printf(“%s”,**++cpp);printf(“%s”,*--*++cpp+3);printf(“ %s”,*cpp[-2]+3);printf(“%s\n”,cpp[-1][-1]+1);}15.Упорядочить вещественный массив х по неубыванию, используяметод сортировки выбором (найти максимальный элемент массива и переставить его с последним элементом; затем применитьэтот же метод ко всем элементам, кроме последнего).16. Упорядочить вещественный массив х по неубыванию, используяметод сортировки обменом ("метод пузырька") (последовательносравнивать пары соседних элементов: x1 с x2, х2 с х3 и т.д., и если первый элемент пары больше второго, то переставлять их –наибольший элемент окажется в конце массива; затем применитьэтот же метод ко всем элементам, кроме последнего).17.Упорядочить вещественный массив х по неубыванию, используяметод сортировки вставками (пусть первые k элементов уже упорядочены по неубыванию; взять (k+1)-ый элемент и разместитьего между первыми k, не нарушая порядок).18.Дан массив, содержащий заданное количество вещественных чисел.
Написать функцию, возвращающую максимальное значениеэтого массива.19.Даны целочисленные массивы X и Y , содержащие по 20 элементов. Написать функцию, которая возвращает значение u.15 20 2x,приxi y i > 0∑∑ii =1U = i =1 202yi , иначе∑i =103720.Описать функцию, определяющую, сколько элементов вещественного массива X из n элементов равны числу у.21.Написать функцию, которой передаются 2 100-элементных целыхмассива, определяющую, составлены ли эти 2 массива из одних итех же чисел без учета порядка их следования, но с учетом повторяющихся чисел (функция возвращает 1 в случае положительногоответа).22.Написать функцию, которая за 1 просмотр циклически сдвигаетполученный вещественный массив на 20 позиций влево (функциядля работы должна использовать вспомогательный массив).23.Написать функции, которым в качестве параметра передаетсямассив указателей на строки.
Признак конца – нулевой указатель.a) Написать функцию, которая распечатывает первые три символа из каждой строки.b) Написать функцию, которая печатает самую длинную строку.c) Написать функцию, которая печатает строки, включающие всебя строку “begin”.24.Распечатать все аргументы командной строки ( без имени вызываемой программы ).25.Если среди параметров командной строки, есть строки, содержащие “end” более одного раза, то распечатать символы этих строк,находящиеся после второго вхождения “end”.26.Написать программу, печатающую имена и значения всех переменных окружения.38ТЕМА 5. Препроцессор10Стандартная схема трансляции Си-программы состоит из двухэтапов: препроцессирование и собственно компиляция.Препроцессор представляет собой предварительную стадиюобработки исходного текста программы, по окончании работы которой модифицированный исходный текст поступает на вход компилятору.Одной из примитивных задач препроцессора является удаление комментариев, а также «склеивание» строчек, последним символом которых является «\», со следующей за ними строкой (эта особенность позволяет программисту осуществлять «перенос» слишкомдлинных строк, например, длинных строковых литералов) и конкатенация рядом стоящих строковых литералов.
Кроме того, препроцессор выполняет макроподстановку, условную компиляцию, подключение файлов.Программный файл может содержать специальные директивыпрепроцессору. Директивам препроцессору предшествует знак #.Например:#include <stdio.h> /* подключение файла */#define a “max=%d\n” /* макроподстановка */int x=15;max(int);main(){ int y, u;scanf(“%d”,&y);u=max(y);printf(a,u);}max(int f){ int k;k=(x>f)?x:f;return k;}Включение файловНа место директивы #include препроцессор подставляет содержимое указанного в ней файла.
Порядок поиска подключаемогофайла зависит от реализации Си. Если имя файла заключено в < >,то он ищется в стандартном каталоге подключаемых файлов (например, в некоторой UNIX-системе это может быть каталог/usr/include), как, например, в случае директивы:Мы не рассматриваем особенности функционирования конкретных трансляторов, аописываем наиболее часто используемые возможности препроцессора.1039#include <stdio.h>Если же имя файла заключено в кавычки и не является полным(абсолютным) путевым именем файла, то препроцессор рассматривает его как относительный путь от местонахождения того файла, вкотором встретился #include.
Например:#include “myfile.h”#include “/usr/stuff/myfile.h”Включаемые файлы, в свою очередь, могут содержать#include-директивы.МакроподстановкаОписание макроподстановки имеет вид:#define имя подставляемый_текстНачиная от места появления #define и до конца файла, везде,где встречается имя, указанное в #define, вместо него препроцессорподставляет заданный подставляемый текст (кроме случаев, когдаэто имя встречается внутри текста в кавычках, т.е. внутри строкового литерала).Примеры:#define NUMBER 10#define DOUBLED_NUMBER NUMBER*2 /*в #defineопределении можно использовать более ранниеопределения11 */#define PrintHello printf(“Hello,\world”); /* “\” используется для продолженияопределения на следующей строке */Можно определить макроподстановку с параметрами, что позволяет изменять подставляемый текст в зависимости от фактических параметров.
Например:#define SQR(x) ((x)*(x))#define Print(x) printf(#x “ = %d\n”, x)/* имя формального параметра, встретившееся в “”, незаменяется на фактический параметр, но если передименем формального параметра стоит #, то вмакрорасширении #имя_формального_параметра будетзаменено на строку “фактический_параметр”, послечего в нашем примере строки конкатенируются */main(){int n = 4;Print(n);/* выводит на печать: n = 4 */Print(SQR(n)); /* SQR(n) = 16 */при этом в текст программы вместо DOUBLED_NUMBER подставится 10*2,а не 201140/* следующие два примера демонстрируют необходимостьскобок в определении SQR(x) для обеспечения нужногопорядка вычислений */Print(SQR(n+2));/* SQR(n+2) = 36 */Print(256/SQR(n)); /* 256/SQR(n) = 16 */}Оператор ## позволяет «склеивать» аргументы в макроподстановке, например:#define bond(left, right) left##rightТаким образом для bond(name, 123) будет сгенерированоname123Примечание.
Повторный #define для того же имени являетсяошибкой, если подставляемые тексты не совпадают с точностью доразделяющих пробельных символов. Препроцессору можно датьуказание «забыть» определенное имя с помощью директивы#undef имя(если имя не было ранее определено, ошибки не произойдет).Важно понимать, что любая макроподстановка, в отличие отвызова функции, обрабатывается не во время выполнения программы, а на этапе ее компиляции (а точнее, препроцессирования). Приэтом никакие вычисления не производятся, а происходит лишь модификация исходного текста программы.Использование в качестве аргументов макроподстановки выражений с побочными эффектами (например, выражений вида x++)может привести к нежелательным последствиям, т.к.
в отличие отфункций, здесь не происходит однократного вычисления аргументапри вызове, и вычисление выражения-параметра произойдет столькораз, сколько оно встречается в замещающем тексте макроподстановки.Условная компиляцияДругой пример использования препроцессора – управление выборочным включением того или иного текста в программу в зависимости от вычисляемого на этапе препроцессирования условия.if-директива выражение_или_идентификатор...[{#elif выражение}...#else... ]#endifгде if-директива – это:#if константное_выражение(вычислить выражение и если получилось ненулевое значение, товключить весь текст до строки else-директивы или #endif)41#ifdef имя /* 1, если имя уже определено */#ifndef имя /*1, если имя не было определено */Например, во избежание повторного включения файла "myfile.h",текст этого файла оформляют следующим образом:#ifndef MYFILE#define MYFILE…содержимоеподключаемогофайла…#endif#if !defined(MYFILE)#define MYFILEили…содержимоеподключаемогофайла…#endif“myfile.h”“myfile.h”Общий порядок действий препроцессора таков:• если в конце строчки исходного текста самым последним символом является «\», он удаляется, а строка«склеивается» со следующей строкой исходного текста;• удаляются комментарии (каждый из них заменяется наодиночный пробел);• выполняются директивы препроцессору;• осуществляются макроподстановки;• если в ходе выполнения директивы #includeпроисходит включение файла, для его текста рекурсивновыполняются все ранее описанные шаги;• конкатенируются рядом стоящие строковые литералы.42ТЕМА 6.
Указатели на функции. Интерпретация сложных деклараций. Оператор typedefУказатели на функцииВ языке Си можно определять указатели на функции, которыеничем не отличаются от обычных указателей. Указатель на функциюможно присваивать, размещать в массиве, передавать в функцию вкачестве параметра. Например:double (*fp)(double);fp – это указатель на функцию с одним параметром типа double,возвращающую значение типа double. Теперь указателю fp можетбыть присвоен адрес любой функции, имеющей такой прототип, после чего его можно будет использовать наравне с именем функции.double x=1.57,y;fp=sin;y=fp(x); /* y=sin(x) – эквивалентно */Задача 1. Написать программу, вычисляющую y=f(x), где имя функции(sin, cos, exp или sqrt) и ее параметр задаются в качестве аргументов командной строки.#include<stdio.h>#include<string.h>#include<math.h>typedef double (*tf)(double);main(int argc,char * argv[]){ char *str[4]={“sin”,”cos”,”exp”,”sqrt”};tf m[4]={sin,cos,exp,sqrt};double x;int i;for(i=0;i<4;i++)if(!strcmp(argv[1],str[i])) break;if(i==4) {printf(“Имя функции задано неверно\n”);return(-1);}x=atof(argv[2]);printf(“%s(%f)=%f\n”,str[i], x, m[i](x));}При передаче функции в качестве параметра ее имя трактуется какадрес этой функции, поэтому оператор & перед ним не нужен (такжекак & был не нужен перед именем массива).Например:void sort(void *vector[],int (*comp)(void*, void*));43/*функция сортировки получает функциюсравнения в качестве параметра */int complen(char *, char *);int lexcomp(char *, char *);main(){ int lexorder;char * strings[];...