Краткий конспект семинарских занятий по языку C - Н.Д. Васюкова_ И.В. Машечкин_ В.В.Тюляева_ Е.М.Шляховая, страница 5
Описание файла
Документ из архива "Краткий конспект семинарских занятий по языку C - Н.Д. Васюкова_ И.В. Машечкин_ В.В.Тюляева_ Е.М.Шляховая", который расположен в категории "". Всё это находится в предмете "операционные системы" из 3 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Онлайн просмотр документа "Краткий конспект семинарских занятий по языку C - Н.Д. Васюкова_ И.В. Машечкин_ В.В.Тюляева_ Е.М.Шляховая"
Текст 5 страницы из документа "Краткий конспект семинарских занятий по языку C - Н.Д. Васюкова_ И.В. Машечкин_ В.В.Тюляева_ Е.М.Шляховая"
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*));
/*функция сортировки получает функцию
сравнения в качестве параметра */
int complen(char *, char *);
int lexcomp(char *, char *);
main()
{ int lexorder;
char * strings[];
... /* заполнение strings */
sort((void **)strings,
(int(*)(void*,void*))(lexorder?lexcomp:complen));
/* явные преобразования нужны для проверки компилятором согласованности типов */
}
Задачи.
-
Ввести набор слов. Слов не более 20-ти. Разделители между словами: пробел, запятая, конец строки. Длина слова не превышает 20 символов. Разместить слова в динамической памяти (лишнего места не занимать) и сформировать массив указателей на слова. Использовать в качестве признака конца массива нулевой указатель NULL. Упорядочить слова в неубывающем порядке. Распечатать слова, каждое на отдельной строке.
-
Написать функции, которым в качестве параметра передается массив указателей на строки. Признак конца – нулевой указатель.
-
Написать функцию, которая распечатывает первые три символа из каждой строки.
-
Написать функцию, которая печатает самую длинную строку.
-
Написать функцию, которая печатает строки, включающие в себя строку “begin”.
-
Ввести набор строк. Количество строк не более 15-ти. Длина каждой строки не должна превышать 80 символов. Под каждую введенную строку зарезервировать в динамической памяти место под реальную ее длину, скопировать туда строку и записать адрес в массив указателей . Признак конца в массиве указателей – NULL( нулевой указатель). Написать функцию, которой передается в качестве параметра массив указателей, а выходное значение – адрес самой большой (лексикографически) строки. Используя этот адрес, распечатать самую большую строку.
Распечатать все аргументы командной строки ( без имени вызываемой программы ).
Если среди параметров командной строки, есть строки, содержащие “end” более одного раза, то распечатать символы этих строк, находящиеся после второго вхождения “end”.
Напечатать таблицу значений функции на отрезке [a,b] с шагом h. Имя функции( sin, cos, tan, log, fabs, sqrt или exp), a,b и h ввести как параметры командной строки. Вызов функций реализовать через массив указателей на функции.
Написать функцию вычисления интеграла f(x) на отрезке [a,b] методом прямоугольников. f(x) – любая функция, интегрируемая на заданном отрезке. Функцию f(x) передавать через параметр-указатель на функцию.
Получить польскую инверсную запись (ПОЛИЗ) выражения, содержащего цифры 0,1, . . . 9, скобки и арифметические операции: *, /, +, - .
Вычислить значение выражения по его ПОЛИЗ’у.
Ввести в качестве аргумента командной строки произвольное скобочное выражение, содержащее числа (целые и вещественные), знаки арифметических операций ( +, -, *, /) и стандартные функции из математической библиотеки. Выражение может содержать параметр Х, тогда и только тогда должен быть предусмотрен ввод конкретного значения. Вычислить это выражение и результат вывести на печать. В качестве усложнения задачи предлагается ввести контроль правильности введенного выражения или не ограничивать число параметров.
Написать программу, печатающую имена и значения всех переменных окружения.
ТЕМА 7. Многомерные массивы и их инициализация. Передача многомерных массивов в качестве параметров функций. Указатель на массив. Интерпретация сложных деклараций. Оператор typedef.
В языке Си массив представляет собой совокупность элементов одного и того же типа. При определении массива указывается тип элементов и их количество в квадратных скобках. Массив можно конструировать из объектов арифметического типа, указателей, структур и объединений, а также других массивов(генерируя при этом многомерные массивы). Например, int m[3][4]; - это определение массива из трех элементов, каждый элемент которого в свою очередь является массивом, состоящим из четырех целочисленных объектов.
В общем случае декларация массива имеет вид:
T D, где D имеет вид
D1[<константное выражение целого типа>] .
Аналогично определяется D1 и т.д.
Доступ к элементам массивов осуществляется через индексирование, например: m[i][j], где i – номер строки, а j – номер столбца. Операция индексирования E1[E2] определена как *(E1+E2), следовательно m[i][j] тождественно *(*(m+i)+j).
Массивы хранятся построчно, т.е. в общем виде быстрее всего изменяется самый правый индекс.
Инициализация многомерных массивов осуществляется аналогично одномерным массивам. Например:
int m[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
Если инициализирующих значений меньше, чем указанная размерность, то соответствующим элементам присваиваются нулевые значения. Например:
int w[3][3]={{1,2,3},{4,5}};
Элементы: w[1][2], w[2][0], w[2][1], w[2][2] примут нулевые значения.
Для многомерных массивов пустой может быть только первая размерность, реальное значение которой определяется по количеству инициализирующих значений. Например, если в выше приведенном примере опустить число строк, то тогда будет определена матрица 2х3.
На примере двумерного целочисленного массива m рассмотрим понятие указателя на массив.
int *p1;
int (*p2)[4];
p1 – это указатель на объект целого типа, ему может быть присвоен адрес любого элемента матрицы m. Например, адрес 0-го элемента 1-ой строки можно присвоить тремя эквивалентными способами:
p1=&m[1][0]; | p1=m[1]; | p1=*(m+1); |
p2 – это указатель на массив из четырех целочисленных элементов и ему может быть присвоен адрес любой строки матрицы, например:
p2=m+1;
Соответственно, оператор p1++; вызывает переход к следующему элементу 1-ой строки, а оператор p2++; вызывает переход к следующей строке матрицы. Тогда *p1=6, а **p2=9.
При передаче двумерного массива в качестве параметра функции возможно три варианта записи заголовка функции:
-
f(int mas[3][4]);
-
f(int mas[][4]);
-
f(int (*p)[4]);
Все три варианта эквивалентны и позволяют пользоваться внутри функции как индексной записью, так и указателями.
Задача 1. Написать функцию, которая вычисляет и распечатывает сумму элементов каждого столбца вещественной матрицы 5х6.
void sum(double (*p)[6])
{ int i,j;
double s,(*pp)[6];
for(i=0;i<6;i++) {
pp=p;
for(j=0,s=0.0; j<5; j++) {
s+=*(*pp+i);
pp++;
}
printf(“%f\n”,s);
}
}
Интерпретация сложных деклараций. В декларациях обычно используется имя (идентификатор) и один из модификаторов *, [ ] и ( ), причем разрешается использовать более одного модификатора в одной декларации8. Для раскрытия этих деклараций применяются следующие правила:
-
Чем ближе модификатор стоит к идентификатору, тем выше его приоритет.
-
Приоритет ( ) и [ ] выше, чем приоритет *.
-
Приоритет повышается заключением в скобки ().
Примеры:
-
Массивы и указатели
int matrix[10][10];
matrix – массив массивов типа int
char **argv;
argv – указатель на указатель на char
int (*ip)[10];
ip – указатель на массив из 10 элементов типа int
int *ip[10];
ip - 10-элементный массив указателей на int
int *ipp[3][4];
ipp - 3-элементный массив указателей на 4-элементный массив типа int
int (*ipp)[3][4];
ipp – указатель на 3-элементный массив, каждый элемент которого - 4-элементный массив типа int
-
Функции и указатели
int *f(); | f – функция, возвращающая указатель на int |
int (*pf)(); | pf – указатель на функцию, возвращающую int |
char (*(*x())[])(); | x – функция, возвращающая указатель на массив указателей на функцию, возвращающую char |
char (*(*x[3])())[5]; | x – массив из 3 указателей на функцию, возвращающую указатель на массив из 5 элементов типа char |
Для упрощения прочтения сложных деклараций, а также для именования, типам данных можно задавать новые имена с помощью оператора typedef9. Например:
typedef double (*PFD)();
определяет тип PFD как “указатель на функцию, возвращающую double”; typedef не создает новый тип, а декларирует новое имя уже существующего типа.
Задачи10.
-
Дано множество точек на плоскости, заданных координатами (x,y). Написать функцию, возвращающую минимальное расстояние между двумя точками.
-
Написать функцию обработки вещественной матрицы (50x20). Функция должна находить строку, содержащую наибольшее количество отрицательных элементов и распечатывать все элементы этой строки. Если таких строк несколько, то печатать все такие строки.
-
Написать функцию, осуществляющую умножение двух матриц порядка MxN и NxK.
-
Что будет выведено на печать?
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][2-i],*a[i],*(*(a+i)+i),*pa[i],p[i]);
}
-
Что будет выведено на печать?
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);
}
ТЕМА 8. Структуры, объединения, битовые поля. Программирование динамических структур данных.
Структура – это тип данных, позволяющий сгруппировать несколько переменных (возможно различного типа) под одним именем. В общем случае декларация структуры имеет следующий вид:
struct[<тег структуры>]{<список деклараций полей>};
Например, для задания комплексных переменных удобно использовать структуру:
struct point { int x;
int y;
} a,b;
В данном примере переменные a и b определены сразу за декларацией структуры, но т.к. структура имеет тег point, переменные можно определить и иначе:
struct point c,d,*p;