А.А. Белеванцев, С.С. Гайсарян, Л.С. Корухова, Е.А. Кузьменкова, В.С. Махнычев. Семинары по курсу Алгоритмы и алгоритмические языки (1108027), страница 10
Текст из файла (страница 10)
Тогда сначала в динамической памяти следуетвыделить место под массив указателей на строки матрицы, а потом местонепосредственно под элементы матрицы. Причем место в памяти под элементы матрицыможет быть выделено как единым блоком, так и для каждой строки матрицы отдельно.7.4. Задачи для самостоятельного решения7.4.1.
На стандартном потоке ввода задана последовательность строк, признакомконца последовательности является пустая строка. Количество строк не более 20.Написать фрагмент программы, который вводит строки, размещает их в динамическойпамяти и формирует массив указателей на эти строки. В качестве признака конца массиваиспользовать нулевой указатель NULL.447.4.2. Описать функцию, которой в качестве параметра передается массивуказателей на строки (признак конца массива – указатель NULL):a) функция выводит на стандартный поток вывода последний символ каждойстроки;b) функция выводит на стандартный поток вывода первые три символа каждойстроки, длина которой больше или равна 3;c) функция выводит на стандартный поток вывода строку максимальной длины;d) функция подсчитывает количество строк, являющихся палиндромами;e) функция упорядочивает строки в лексикографическом порядке.7.4.3.
Описать функцию, которая выделяет в динамической памяти место подцелочисленную матрицу размера n × m при условии, что память под каждую строкуматрицы выделяется отдельно. Функция возвращает указатель на матрицу или NULL, есливыделить память нужного размера не удалось.7.4.4. Описать функцию, которая освобождает в динамической памяти место, ранеевыделенное под целочисленную матрицу размера n × m, при условии, что:a) память под элементы матрицы выделялась единым блоком;b) память под каждую строку матрицы выделялась отдельно.7.4.5.
На стандартном потоке ввода задано число n (n > 2) и элементы трехквадратных целочисленных матриц размера n × n . Используя для размещения матрицдинамическую память, ввести эти матрицы и распечатать ту из них, в которой большенулевых строк (считать, что такая матрица только одна).8. Структуры и объединения.Структуры.
Описание типов структур и переменных этого типа. Операции надструктурами. Объединения. Задачи.8.1. СтруктурыСтруктурный тип позволяет работать с совокупностью нескольких переменных как сединым целым. Переменные, являющиеся составными частями структуры, называютсяполями. Поля структуры могут быть любого типа.Описание структурного типа выглядит следующим образом:struct [ <имя_типа_структуры> ] '{' <список_полей> '}' [<переменные> ] ';'где<имя_типа_структуры> – идентификатор. В дальнейшем можно ссылаться наописанный тип при помощи конструкции вида struct <имя_структуры>. Этотидентификатор может быть опущен, в таком случае описываются только переменныеанонимного структурного типа, а после описания завести новые переменные того же типауже невозможно;<список_полей> – одно или более описаний переменных, являющихся составнымичастями структуры.
Эти описания имеют тот же синтаксис, что и описания обычныхпеременных в Си; при этом имена переменных в этих описаниях становятся именамисоответствующих полей структуры. Поля могут быть любого типа, простого илисоставного, включая массивы и другие структуры. Поле структуры не может быть VLAмассивом;45<переменные> – список описываемых переменных, типом которых является толькочто объявленный структурный тип. Если этот список пуст, то описывается толькоструктурный тип (в этом случае имя типа структуры не может быть опущено).Имена полей структуры, а также имена типов структур имеют отдельные областивидимости и могут совпадать с именами других объектов программы.Описание структурного типа всегда описывает новый тип, не совпадающий ни скаким из ранее описанных (даже если список полей полностью совпадает со спискомполей какого-либо другого структурного типа, описанным ранее).Пример 1.
Описание структурного типа для хранения информации о студенте:struct student {char name[80]; // поле name – массив из 80 символов (строка)int group; // поле group – целое числоchar city[30]; // поле city – массив из 30 символов} st1, st2; // переменные st1 и st2 имеют тип struct studentstruct student course[400]; // массив из 400 структур типа// struct studentstruct student *ps; // указатель на struct studentПример 2. Описание структурного типа для хранения комплексного числа:struct complex {double re, im;}; /* непосредственно при описании типа структуры не описаныникакие переменные */struct complex x, y; // x и у – переменные типа struct complexПолями структуры, в свою очередь, могут быть другие структуры, то естьвозможны вложенные структуры.Над переменными структурного типа определены следующие операции:1.
Операция взятия адреса ( & ).2. Копирование и присваивание (для структур одного типа). При присваиваниикопируются значения всех полей структуры. Структуры можно передавать как параметры(по значению) в функцию, можно возвращать как результат функции.3. Обращение к отдельному полю структуры. Для обращения используется оператор'.' (точка) в конструкции вида:<переменная> . <имя_поля>где <переменная> – переменная структурного типа. С полем структуры можновыполнять все действия, которые определены для типа, которому принадлежит это поле.При обращении к полю структуры по указателю на структуру можно использоватьоператор '->' (стрелка): a -> b эквивалентно (*а).b.Приоритет операторов обращения к полям структуры ( .
и -> ) — наиболеевысокий.46Примеры (с учетом приведенных выше описаний):st1.group = 101; // значение поля group в перем. st1 равно 101strcpy (st1.city, "Москва");st2 = st1; // значения всех полей st1 копируются в поля st2p = &st1; // p указывает на st1(*p).group++; /* увеличение поля group структуры, на которуюуказывает р (т.е. St1) */p->group++; // то же, что и в предыдущей строкеx.re += y.re;x.im += y.im; // сложение комплексных чисел х и уНикакие операции сравнения, а также арифметические или логические операциинад структурами не определены:if (x == y) … // ошибка!// Правильнее: if (x.re == y.re && x.im == y.im) .x = x + y; // ошибка!x++; // ошибка!x.group = 102; // ошибка! В struct complex нет поля group.st1 = x; // ошибка! Присваивание структур разных типов.Оператор sizeof для структуры возвращает размер (в байтах) области памяти,отводимой компилятором под хранение структуры.
Размер структуры в байтах всегда неменьше суммы размеров всех ее полей (может быть больше):sizeof(struct complex)=sizeof(x) >= sizeof(double)+sizeof(double)= 16При описании переменных-структур возможна их полная или частичнаяинициализация (как и в случае с массивами):struct student st3 = {"Смирнов П.В.", 104, "Калуга"};struct student st4 = {"Кузнецова А.Ю."};Не указанные в инициализации поля структуры получают нулевое значение вслучае, если явно инициализировано хотя бы одно поле структуры. Если инициализациявообще не производится, то, как и для обычных переменных, глобальные структурыполучат нулевые значения, а локальные – не будут инициализированы по умолчанию.Задача 1.
Используя описанный выше тип struct complex, описать функцию длявычисления произведения двух комплексных чисел.Возможны два варианта решения:// Первый вариант: передача параметров по значениюstruct complex mul (struct complex a, struct complex b) {struct complex m;m.re = a.re*b.re – a.im*b.im;m.im = a.re*b.im + a.im*b.re;return m;}47// пример вызова:c = mul (x,y);// Второй вариант: передача параметров по указателюstruct complex mul (struct complex *a, struct complex *b) {struct complex m;m.re = a->re * b->re – a->im * b->im;m.im = a->re * b->im + a->im * b->re;return m;}// пример вызова:c = mul (&x,&y);Второй вариант решения более эффективен: при вызове такой функции невыполняется копирование содержимого параметров a и b.Задача 2.
Что будет напечатано в результате исполнения следующего фрагментапрограммы?а)struct st { char *s; } t1, t2;t1.s = malloc(10);strcpy (t1.s, "Hello ");t2 = t1;printf ("%s", t2.s);strcpy (t1.s, "world!");printf ("%s", t2.s);Поскольку при копировании структур происходит побайтовое копированиезначений их полей, то в результате выполнения присваивания t2=t1 скопируютсяуказатели: поле t2.s будет указывать на ту же область памяти, что и t1.s (сама областьпамяти скопирована не будет). В результате выведется: “Hello world!”.б)struct st { char s[10]; } t1, t2;strcpy (t1.s, "Hello ");t2 = t1;printf ("%s", t2.s);strcpy (t1.s, "world!");printf ("%s", t2.s);В данном случае полем структуры является массив из 10 символов, и приприсваивании структур все его содержимое будет скопировано. В результате выведется“Hello Hello ”.8.2.
ОбъединенияОбъединения в Си описываются так же, как и структуры, но для их описанияиспользуется ключевое слово union:48union u {int i;double f;} tmp;Объединения имеют одно принципиальное отличие от структур: все поляобъединения располагаются в памяти начиная с одного и того же базового адреса и, такимобразом, изменение одного поля объединения влечет за собой потенциальное изменениевсех остальных полей объединения (в структуре же все поля независимы и располагаютсяв памяти без наложений друг на друга).Обычно только одно из полей объединения имеет смысл в каждый конкретныймомент времени. Какое из полей использовать – определяет программист. Например,описанную выше переменную tmp можно использовать для хранения целого числа иливещественного числа, но не для обоих чисел одновременно.Объединения могут также использоваться для организации доступа к отдельнымчастям значений, например:union intbytes {int number;unsigned char bytes[4];} d;d.number = 12345678;printf ("Побайтовое представление числа %d в памяти""имеет вид: %d %d %d %d\n", d.number,d.bytes[0], d.bytes[1], d.bytes[2], d.bytes[3]);Над объединениями определены те же операции, что и над структурами.Размер объединения в памяти определяется размером наибольшего поля вобъединении.8.3.