Язык программирования С Тема «Типы данных, операции и

Скачать презентацию Язык программирования С Тема «Типы данных, операции и Скачать презентацию Язык программирования С Тема «Типы данных, операции и

Lekcija-04-05.ppt

  • Количество слайдов: 45

>Язык программирования С Тема «Типы данных, операции и выражения» (продолжение) Лекция  26.09.11г. 1 Язык программирования С Тема «Типы данных, операции и выражения» (продолжение) Лекция 26.09.11г. 1

>Лекция  26.09.11г. 2 Обзор вопросов прошлой лекции Строковые константы Константы перечислимого типа Объявления Лекция 26.09.11г. 2 Обзор вопросов прошлой лекции Строковые константы Константы перечислимого типа Объявления переменных Операции, виды операций Арифметические операции Операции отношения Логические операции Операции инкремента и декремента Поразрядные (битовые) операции

>Лекция  26.09.11г. 3 Операции с присваиванием В языке С операция присваивания немного отличается Лекция 26.09.11г. 3 Операции с присваиванием В языке С операция присваивания немного отличается от аналогичной операции в других языках: Присваивание a = b действительно является операцией (а не оператором), т.е. после завершения этой операции получается некоторое значение (в данном примере – значение переменной b), которое может быть использовано для последующих вычислений. Следовательно, присваивание может применяться внутри выражений, наряду с другими операциями. #include #include int main() { int a = 12, b, c; printf("result = %d \n", c=(b=a)-5); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 4 Операции с присваиванием (продолжение) Кроме обычного присваивания существует ещё 10 Лекция 26.09.11г. 4 Операции с присваиванием (продолжение) Кроме обычного присваивания существует ещё 10 модификаций, в которых присваивание совмещается с какой-либо бинарной операцией, например, k += 2 эквивалентно k = k + 2, или ещё: x >>= 1 эквивалентно x = x >> 1 и т.д. Полный перечень бинарных операций, совмещаемых с присваиванием: + - * / % << >> & ^ | #include #include // Подсчет количества единичных битов в двух байтах int main() { unsigned short x = 0x1234; int b; for (b=0; x!=0; x >>= 1) if (x & 01) b++; printf("the number of bits = %d \n", b); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 5 Тернарная условная операция Во многих алгоритмах часто встречается конструкция вида: Лекция 26.09.11г. 5 Тернарная условная операция Во многих алгоритмах часто встречается конструкция вида: if ( условие) x=<выраж1>; else x=<выраж2>; Иными словами, переменная x получает значение одного из двух выражений, в зависимости от истинности условия. В языке С для компактной записи подобного фрагмента существует специальная тернарная условная операция: x = условие ? <выраж1> : <выраж2> #include #include #define N 57 int main() { int i, x[N]; for (i=0; i

>Лекция  26.09.11г. 6 Приоритет и ассоциирование операций Всего операций: 47 Лекция 26.09.11г. 6 Приоритет и ассоциирование операций Всего операций: 47

>Лекция  26.09.11г. 7 Приоритет и ассоциирование операций Операции, находящиеся в одной строке таблицы Лекция 26.09.11г. 7 Приоритет и ассоциирование операций Операции, находящиеся в одной строке таблицы , принадлежат одной группе: имеют одинаковый приоритет и одинаковый порядок выполнения (слева направо или наоборот). Все 47 операций распределены по 15 группам, группа 1 имеет наивысший приоритет, а группа 15 наинизший приоритет. 1-я группа: () - вызов функции, [] – доступ к элементу массива, -> - обращение к элементу структуры через указатель, . - обращение к элементу структуры через имя структуры. 2-я группа (унарные операции): + - - унарные «плюс» и «минус», * - «разыменование» указателя, т.е. обращение к объекту, на который он указывает, & - получение адреса объекта, (тип) – приведение типа операнда, sizeof – определение размера объекта. … 15-я группа: , - операция «запятая» - это бинарная операция имеющая вид: выражение1 , выражение2. Действие операции заключается в последовательном вычислении выражений, а её результатом является значение второго выражения.

>Лекция  26.09.11г. 8 Иллюстрация к операциям #include <stdio.h> #include <stdlib.h> int main() { Лекция 26.09.11г. 8 Иллюстрация к операциям #include #include int main() { int i, s, x[] = {1, 3, 5, 7, 9}; for(i = 0, s = 0; i < sizeof(x)/sizeof(x[0]); s+=x[i++]); printf("s = %d\n", s); system("PAUSE"); return 0; } кол-во элем. массива операция «запятая»

>Лекция  26.09.11г. 9 Иллюстрация к приоритету операций #include <stdio.h> #include <stdlib.h> int main() Лекция 26.09.11г. 9 Иллюстрация к приоритету операций #include #include int main() { int x = 4, y = 6, k = 5, i = 1; y*=x+=--k<<++i; printf("y = %d, x = %d, k = %d, i = %d\n", y, x, k, i); system("PAUSE"); return 0; } Чему равно значение переменной y после вычисления выражения: y*=x+=--k<<++i 1 2 3 4 5

>Лекция  26.09.11г. 10 Преобразование (приведение) типов Приведение типа (type conversion) — преобразование значения Лекция 26.09.11г. 10 Преобразование (приведение) типов Приведение типа (type conversion) — преобразование значения одного типа в значение другого типа. Выделяют явное и неявное приведения типов. при явном приведении с помощью унарной операции (тип) указывается тип, к которому необходимо преобразовать значение выражения, расположенного справа от этой операции; при неявном приведении преобразование происходит автоматически, по правилам, заложенным в языке программирования. int main() { int x = 32768, y = 65535; short sx = 32768, sy = 65535; char c1 = 32768, c2 = 65535; unsigned z = 0xffffffff; float fz = 0xffffffff; printf("%d %d %d %f %d\n", x, (short)x, sx, (float)x, c1); printf("%d %d %d %f %d\n", y, (short)y, sy, (float)y, c2); printf("%u %f %f %f\n", z, (float)z, (double)z, fz); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 11 Преобразование (приведение) типов Корректными преобразования типов, не вызывающими искажения значений Лекция 26.09.11г. 11 Преобразование (приведение) типов Корректными преобразования типов, не вызывающими искажения значений или потери точности, являются приведения более «узких» типов к более «широким». Если же значение более «широкого» типа приводится к более «узкому» типу, возможно искажение значения или потеря точности, о чем выдает предупреждение (warning) компилятор. Явные преобразования типов всегда происходят по «инициативе» программиста, а инициатором неявных преобразований выступает компилятор в тех случаях, когда при выполнении операции ожидается один тип, а фактически присутствует другой тип. Замечание. В некоторых случаях неявное преобразование бывает просто неосуществимым «по определению». Например, в выражении 3.0%2.0 значения 3.0 и 2.0 не преобразуется автоматически к целому типу, т.к. операция % применима только к целочисленным значениям и поэтому компилятор выдаст сообщение об ошибке (error).

>Тема  «Управляющие конструкции языка С» Лекция  26.09.11г. 12 Тема «Управляющие конструкции языка С» Лекция 26.09.11г. 12

>Лекция  26.09.11г. 13 Простые операторы и блоки Если в конце любого выражения поставить Лекция 26.09.11г. 13 Простые операторы и блоки Если в конце любого выражения поставить символ ; (точка с запятой), получим элементарную «строительную конструкцию» программы – простой оператор: z = foo(x+y); x+=y; 2=4*5; … Простые операторы в программе могут располагаться последовательно, друг за другом: temp = x+y; z = foo(temp); Последовательность простых операторов можно заключить в фигурные скобки { и }. В этом случае получится составной оператор, или, иначе – блок, который синтаксически эквивалентен простому оператору и компилируется как самостоятельная конструкция. После закрывающей скобки точка с запятой не ставится. Блок может быть пустым: {}

>Лекция  26.09.11г. 14 Простые операторы и блоки Внутри блока можно размещать объявления переменных: Лекция 26.09.11г. 14 Простые операторы и блоки Внутри блока можно размещать объявления переменных: { int temp = x+y; z = foo(temp); } Такие переменные будут локальными; они будут создаваться при входе в блок и исчезать при выходе из блока. За пределами блока локальные переменные невидимы. Блоки могут быть вложенными (глубина вложенности не ограничивается) { int temp = x+y; z = foo(temp); { float temp2 = x∗y; z += bar(temp2); } }

>Лекция  26.09.11г. 15 Операторы простого выбора В простейшем случае требуется выбрать для выполнения Лекция 26.09.11г. 15 Операторы простого выбора В простейшем случае требуется выбрать для выполнения определенный оператор, если некоторое условие истинно (т.е. его значение отлично от 0). Это записывается так: if (условие) оператор Например: if (x%2) y += x/2; Т.е. если x – нечетно, то y увеличивается, в противном случае ничего не делается. Если при выполнении условия нужно выполнить последовательность операторов, необходимо использовать блок В другом случае требуется выбрать для выполнения один из двух операторов, в зависимости от некоторого условия: if (условие) оператор1 else оператор2 Например: if (a>b) c=a; else c=b;

>Лекция  26.09.11г. 16 Вложенные операторы выбора a>b d = a ≠0 =0 Если Лекция 26.09.11г. 16 Вложенные операторы выбора a>b d = a ≠0 =0 Если в качестве исполняемого оператора в операторе выбора используется другой оператор выбора, возникает ситуация вложенности операторов выбора. Пример: найти: d = max(a, b, c) d = b d = c a>c d = c b>c ≠0 =0 =0 ≠0 #include #include int main() { int a = 4, b = 15, c = 7, d; if (a>b) if (a>c) d = a; else d = c; else if (b>c) d = b; else d = c; printf("max = %d\n", d); system("PAUSE"); return 0; } оператор1 оператор2

>Лекция  26.09.11г. 17 Вложенные операторы выбора a>b d = a ≠0 =0 Модифицируем Лекция 26.09.11г. 17 Вложенные операторы выбора a>b d = a ≠0 =0 Модифицируем алгоритм: d = b a>c d = c b>c ≠0 =0 ≠0 #include #include int main() { int a = 4, b = 15, c = 7, d = c; if (a>b) if (a>c) d = a; else if (b>c) d = b; printf("max = %d\n", d); system("PAUSE"); return 0; } =0 Неверно! … if (a>b) {if (a>c) d = a;} else if (b>c) d = b; … Нужно так!

>Лекция  26.09.11г. 18 Множественный выбор Фрагмент алгоритма программы «Калькулятор»: …   if Лекция 26.09.11г. 18 Множественный выбор Фрагмент алгоритма программы «Калькулятор»: … if (c==‘+’) r = a + b; else if (c==‘+’) r = a + b; else if (c==‘-’) r = a - b; else if (c==‘*’) r = a * b; else if (c==‘/’) r = a / b; else printf(“error!\n"); …

>Лекция  26.09.11г. 19 Оператор множественного выбора switch Для алгоритмов с множественным выбором существует Лекция 26.09.11г. 19 Оператор множественного выбора switch Для алгоритмов с множественным выбором существует специальный оператор: … switch(c){ case '+': r = a + b; break; case '-': r = a - b; break; case '*': r = a * b; break; case '/': r = a / b; break; default: printf(“error!\n"); } …

>Лекция  26.09.11г. 20 Важное замечание! При отсутствии операторов break реализуется совсем другой алгоритм: Лекция 26.09.11г. 20 Важное замечание! При отсутствии операторов break реализуется совсем другой алгоритм: c==‘+’ r = a+b =0 ≠0 =0 ≠0 =0 c==‘-’ c==‘*’ c==‘/’ r = a-b r = a*b r = a/b Ошибка! ≠0 ≠0 =0 … switch(c){ case '+': r = a + b; case '-': r = a - b; case '*': r = a * b; case '/': r = a / b; default: printf(“error!\n"); } …

>Лекция  26.09.11г. 21 Оператор множественного выбора switch Общий вид оператора switch: switch (выражение) Лекция 26.09.11г. 21 Оператор множественного выбора switch Общий вид оператора switch: switch (выражение) { case констант-выраж1: операторы case констант-выраж2: операторы … default: операторы } Действие оператора: вычисляется значение выражения и это значение последовательно сравнивается со значениями константных выражений в блоках case. Если произошло совпадение значений, выполняются операторы соответствующего блока case. Как правило, последним оператором в каждом блоке case является оператор break («прервать») и поэтому по завершению выбранного case-блока вычислительный процесс выходит за пределы оператора switch. Если совпадения значений не произошло ни для одного из case-блоков, то выполняются операторы блока default (если он есть) или вычислительный процесс сразу выходит за пределы оператора switch.

>Лекция  26.09.11г. 22 Иллюстрация оператора switch #include <stdio.h> #include <stdlib.h> int main() { Лекция 26.09.11г. 22 Иллюстрация оператора switch #include #include int main() { int c, i, nwhite, nother, ndigit[10]; nwhite = nother = 0; for (i = 0; i < 10; i++) ndigit[i] = 0; while ((c = getchar()) != '$') { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ndigit[c-'0']++; break; case ' ': case '\n': case '\t': nwhite++; break; default: nother++; break; } } printf("digits ="); for (i = 0; i < 10; i++) printf(" %d", ndigit[i]); printf(", white space = %d, other = %d\n", nwhite, nother); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 23 Операторы повторения (цикла) Во многих алгоритмах встречается элементарная конструкция, приведенная Лекция 26.09.11г. 23 Операторы повторения (цикла) Во многих алгоритмах встречается элементарная конструкция, приведенная на блок-схеме. Она соответствует многократному (циклическому) повторению оператора (или нескольких операторов в блоке), пока некоторое выражение не станет равным нулю (получит значение «ложь»). Это записывается так: while(выражение) оператор Такая конструкция называется циклом с предусловием. #include #include int main() { int i = 0; char s[] = "qwerty"; while (s[i++]) ; printf("number of characters(%s) = %d\n", s, --i); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 24 Операторы повторения (цикла) В языке С существует еще одна форма Лекция 26.09.11г. 24 Операторы повторения (цикла) В языке С существует еще одна форма цикла с предусловием, более сложная по сравнению с простейшей формой while. В этой форме дополнительно участвуют еще два выражения, одно из которых вычисляется однократно, до проверки условия, а второе – многократно, после всех операторов, выполняемых в цикле. Это записывается так: for(выраж1; выраж2; выраж3) оператор В круглых скобках любое из выражений можно опустить, но точки с запятой обязательно должны присутствовать. Если опущено выраж2, то оно считается =1. Поэтому конструкция: for(;;); является бесконечным циклом (как, впрочем, и конструкция while(1);

>Лекция  26.09.11г. 25 Пример цикла Следующая программа преобразует символьное изображение числа, записанное в Лекция 26.09.11г. 25 Пример цикла Следующая программа преобразует символьное изображение числа, записанное в строке s, в само число. #include #include #include int main() { int i, n, sign; char s[] = " -347ab"; for (i = 0; isspace(s[i]); i++) ; /* skip white space */ sign = (s[i] == '-') ? -1 : 1; if (s[i] == '+' || s[i] == '-') i++; /* skip sign */ for (n = 0; isdigit(s[i]); i++) n = 10 * n + (s[i] - '0'); n*=sign; printf("s = %s\nn = %d\n", s, n); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 26 Еще один пример цикла Следующая программа обращает порядок символов в Лекция 26.09.11г. 26 Еще один пример цикла Следующая программа обращает порядок символов в строке s. #include #include int main() { int i, j; char s[] = "qwertyuiop", c; printf("before: %s\n", s); for (i = 0, j = strlen(s)-1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } printf("after: %s\n", s); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 27 Оператор цикла с постусловием В некоторых случаях тело цикла должно Лекция 26.09.11г. 27 Оператор цикла с постусловием В некоторых случаях тело цикла должно быть выполнено хотя бы один раз, вне зависимости от истинности выражения. Это может быть реализовано, если проверка значения выражения будет располагаться после тела цикла. Это записывается так: do оператор while(выражение); Такая конструкция называется циклом с постусловием. Цикл с постусловием применяется на практике значительно реже, чем цикл с предусловием.

>Лекция  26.09.11г. 28 Пример цикла с постусловием #include <stdio.h> #include <stdlib.h> int main() Лекция 26.09.11г. 28 Пример цикла с постусловием #include #include int main() { int i = 0, j, sign, n = -347; char s[10], c; if ((sign = n) < 0) /* record sign */ n = -n; /* make n positive */ do { /* generate digits in reverse order */ s[i++] = n % 10 + '0'; /* get next digit */ } while ((n /= 10) > 0); /* delete it */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; printf("inverse: %s\n", s); for (i = 0, j = strlen(s)-1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; } printf("result: %s\n", s); system("PAUSE"); return 0; } Эта программа преобразует число n в его символьное изображение, записанное в строке s. Обращение строки s

>Лекция  26.09.11г. 29 Оператор break  Иногда возникает необходимость прервать выполнение тела цикла Лекция 26.09.11г. 29 Оператор break Иногда возникает необходимость прервать выполнение тела цикла и «досрочно» выйти за пределы цикла. Это можно сделать, разместив в теле цикла оператор break. Это оператор вызывает «безусловный переход» в точку программы, расположенную непосредственно за циклом. Оператор break может использоваться в любом операторе цикла, а также в операторе множественного выбора switch. Пример: программа удаляет «незначащие» символы в конце строки s. #include #include int main() { int n; char s[] = "qwerty \t\t \n\n"; printf("before:\n"); printf("number of characters(%s) = %d\n", s, strlen(s)); for (n = strlen(s)-1; n >= 0; n--) if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n') break; s[n+1] = '\0'; printf("after:\n"); printf("number of characters(%s) = %d\n", s, strlen(s)); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 30 Оператор continue Этот оператор похож на break, но, в отличие Лекция 26.09.11г. 30 Оператор continue Этот оператор похож на break, но, в отличие от break, досрочно прекращает выполнение текущей итерации цикла, а не всего оператора цикла. Для циклов while и do это означает переход к проверке условия, а для цикла for – вычисление выражения3, а уже затем переход к проверке условия. Пример: подсчитать количество положительных элементов массива и найти их среднее арифметическое. #include #include int main() { int x[] = {-1, 4, 0, -3, -7, 5, 11, -2}, i, n; double s; for(i = 0, n = 0, s = 0.0; i < sizeof(x) / sizeof(x[0]); i++) { if(x[i] <= 0) continue; s += x[i]; n++; } if(n) s /= n; printf("number of positive elements = %d\n", n); printf("mean value = %f\n", s); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 31 Оператор перехода goto и метки Оператор goto метка вызывает безусловный Лекция 26.09.11г. 31 Оператор перехода goto и метки Оператор goto метка вызывает безусловный переход к оператору (в той же самой функции) перед которым записана метка (обычное имя, заканчивающееся символом : - двоеточие). Пример: проверить, имеют ли два массива хотя бы один общий элемент. #include #include int main() { int a[] = {-1, 4, 0, -3, -7, 5, 11, -2}, i; int b[] = {7, -12, 8, 9, 11, -2}, j; int n = sizeof(a) / sizeof(a[0]); int m = sizeof(b) / sizeof(b[0]); for (i = 0; i < n; i++) for (j = 0; j < m; j++) if (a[i] == b[j]) goto found; printf("no common elements\n"); goto final; found: printf("common elements: a[%d] == b[%d]\n", i, j); final: system("PAUSE"); return 0; }

>Лекция  26.09.11г. 32 Оператор перехода (продолжение) Оператор goto является «нежелательным» оператором, т.к. «запутывает» Лекция 26.09.11г. 32 Оператор перехода (продолжение) Оператор goto является «нежелательным» оператором, т.к. «запутывает» логическую структуру программы, однако бывают ситуации, когда программа без goto получается более громоздкой, чем с goto. Пример: предыдущая программа без goto. #include #include int main() { int a[] = {-1, 4, 0, -3, -7, 5, 11, -2}, i; int b[] = {7, -12, 8, 9, 11, -2}, j, found = 0; int n = sizeof(a) / sizeof(a[0]); int m = sizeof(b) / sizeof(b[0]); for (i = 0; i < n && !found; i++) for (j = 0; j < m && !found; j++) if (a[i] == b[j]) found = 1; if (found) printf("common elements: a[%d] == b[%d]\n", i, j); else printf("no common elements\n"); system("PAUSE"); return 0; }

>Тема  «Функции и структура программы» Лекция  26.09.11г. 33 Тема «Функции и структура программы» Лекция 26.09.11г. 33

>Лекция  26.09.11г. 34 Функции и модульность программы Модульность в языках программирования — принцип, Лекция 26.09.11г. 34 Функции и модульность программы Модульность в языках программирования — принцип, согласно которому программное средство - ПС (программа, библиотека, web-приложение и др.) разделяется на отдельные сущности, называемые модулями. Модульность позволяет упростить задачи проектирования ПС и распределения процесса разработки ПС между группами разработчиков, а также позволяет реализовать методологию повторного использования кода. При разбиении ПС на модули для каждого модуля указывается реализуемая им функциональность, а также связи с другими модулями. Роль модулей могут играть структуры данных, библиотеки функций, классы, сервисы и др. программные единицы, реализующие некоторую функциональность и предоставляющие интерфейс к ней. В языке С модульность поддерживается функциями, препроцессоными командами, многофайловой структурой программы и заголовочными файлами.

>Лекция  26.09.11г. 35 Функции и модульность программы Функции разбивают большие вычислительные задачи на Лекция 26.09.11г. 35 Функции и модульность программы Функции разбивают большие вычислительные задачи на более мелкие и позволяют инкапсулировать («упрятать» в оболочку) детали реализации некоторой функциональности, предоставив пользователям («клиентам») формат обращения к этой функциональности (интерфейс). Это делает программу в целом более ясной и облегчает внесение в нее изменений. Пример: функция, преобразующая символьное изображение числа, записанное в строке, в само число. #include int atoi_ (char s[]) { int i, n, sign; for (i = 0; isspace(s[i]); i++) ; sign = (s[i] == '-') ? -1 : 1; if (s[i] == '+' || s[i] == '-') i++; for (n = 0; isdigit(s[i]); i++) n = 10 * n + (s[i] - '0'); return sign * n; } #include #include int atoi_ (char[]); int main() { int n = atoi_(" -347ab"); printf("n = %d\n", n); system("PAUSE"); return 0; } интерфейс реализация

>Лекция  26.09.11г. 36 Определение функции Для того, чтобы использовать функцию, ее необходимо определить., Лекция 26.09.11г. 36 Определение функции Для того, чтобы использовать функцию, ее необходимо определить., т.е. описать её интерфейс (т.е. объяснить, как функцией можно воспользоваться) и привести программный код, раскрывающий, как функция работает (т.е. записать реализацию функции на языке программирования). Определение любой функции имеет следующую форму: тип_возвращ_знач имя_функции(список_объявлений_арг) { объявления и операторы } Различные части этого определения могут отсутствовать, но обязательными являются: имя_функции, пара круглых скобок и пара фигурных скобок, т.е. «минимальная» функция определяется так: fun(){} Это – «пустышка», которая не принимает никаких аргументов и ничего не делает (имеет пустое «тело»). Подобные функции могут использоваться в качестве «заглушек» при разработке программ. Если при объявлении функции не указан тип возвращаемого значения, то по умолчанию подразумевается тип int.

>Лекция  26.09.11г. 37 Функции и программы Любая программа является набором определений типов, переменных Лекция 26.09.11г. 37 Функции и программы Любая программа является набором определений типов, переменных и функций. Функции обмениваются данными посредством передачи аргументов и возвращения значений, а также через внешние переменные. Функции могут следовать друг за другом в файле исходного кода в любом порядке, и текст программы можно разбивать на любое количество файлов, но при этом запрещается делить текст функции между файлами. В результате своей работы функция может возвратить в вызывающую ее функцию результат – некоторое значение, тип которого объявлен перед именем функции. Для этого в теле функции должен присутствовать хотя бы один оператор возврата вида: return выражение; Вызывающая функция может игнорировать (т.е. не использовать) возвращаемое значение. Существует еще одна форма оператора возврата: return; В этом случае в вызывающую функцию ничего не передается. Тело функции может не содержать оператора возврата return ; при этом возврат из функции происходит при достижении конца блока (закрывающей скобки } ).

>Лекция  26.09.11г. 38 Пример программы с модульной структурой Разработать программу решения линейных диофантовых Лекция 26.09.11г. 38 Пример программы с модульной структурой Разработать программу решения линейных диофантовых уравнений с двумя неизвестными: ax + by = c , где - a, b, c, x, y – целые числа ; a и b - не нули. К подобному уравнению сводится решение известной олимпиадной задачи: «Предположительно известно, что некоторый ценный предмет (золотой самородок) весит 20 граммов. Требуется убедиться в этом, взвесив его на обычных рычажных весах, но в нашем распоряжении имеются только гири двух типов – на 2 и на 7 граммов, по 5 штук каждого типа. Можно ли в этих условиях произвести взвешивание? Сколько гирь одного и другого типа нужно взять? Сколько существует вариантов взвешивания?» Очевидно, что для получения ответа нужно, как минимум, решить уравнение: 2x + 7y = 20 Точнее говоря, найти множество решений …

>Лекция  26.09.11г. 39 Алгоритм решения диофантова уравнения Алгоритм D. Даны три целых числа: Лекция 26.09.11г. 39 Алгоритм решения диофантова уравнения Алгоритм D. Даны три целых числа: a, b, c (a и b - не нули). Требуется найти два целых числа x и y таких, что ax + by = c . D1. [Нахождение наибольшего общего делителя a и b.] Пользуясь алгоритмом Евклида, найти g - наибольший общий делитель a и b. D2. [Проверка существования решения.] Если с % g ≠ 0, то решения не существует и выполнение алгоритма прекращается. DЗ. [Решение вспомогательного уравнения au + bv = g.] Пользуясь расширенным алгоритмом Евклида, найти u и v . D4. [Получение результата.] Результатом решения исходного уравнения будут множества значений: x = u*(c/g) – (b/g)*t, y = v*(c/g) + (a/g)*t, где t=0, ±1, ±2, …♦ Алгоритм Евклида был рассмотрен ранее. Рассмотрим расширенный алгоритм Евклида (алгоритм EE).

>Лекция  26.09.11г. 40 Расширенный алгоритм Евклида Алгоритм EE. Даны два целых числа: a, Лекция 26.09.11г. 40 Расширенный алгоритм Евклида Алгоритм EE. Даны два целых числа: a, b (a и b - не нули). Требуется найти два целых числа x и y таких, что ax + by = g (где g - наибольший общий делитель a и b). EE1. [Установка начальных значений.] Положить x1=0, x2=1, y1=1, y2=0. EE2. [Цикл с предусловием.] Если b = 0, то решение найдено и перейти к EE4. EEЗ. [Тело цикла.] Вычислить: q=a/b, r=a-q*b, a=b, b=r, x=x2-q*x1, y=y2-q*y1, x2=x1, x1=x, y2=y1, y1=y . Перейти к шагу EE2. EE4. [Получение результата.] Положить g=a, x=x2, y=y2 ♦ #include #include int main() { int a, b, q, r, x1 = 0, x2 = 1, y1 = 1, y2 = 0; int a0, b0, x, y, g; printf("Input a: "); scanf("%d", &a); a0 = a; printf("Input b: "); scanf("%d", &b); b0 = b; while (b) {q = a / b; r=a-q*b; a=b; b=r; x=x2-q*x1; y=y2-q*y1; x2=x1; x1=x; y2=y1; y1=y; } g=a; x=x2; y=y2; printf("Result: %d*(%d)+%d*(%d)=%d\n", a0,x,b0,y,g); system("PAUSE"); return 0; }

>Лекция  26.09.11г. 41 Создание отдельных модулей Оформим теперь оба алгоритма (E и EE) Лекция 26.09.11г. 41 Создание отдельных модулей Оформим теперь оба алгоритма (E и EE) в виде функций языка С. Алгоритм Е (модифицированный): int euclid(int a, int b) { while (a && b) if(a>=b) a%=b; else b%=a; return a + b; } Алгоритм ЕЕ: extern int x, y; int e_euclid(int a, int b) { int q, r, x1 = 0, x2 = 1, y1 = 1, y2 = 0; while (b) { q = a / b; r=a-q*b; a=b; b=r; x=x2-q*x1; y=y2-q*y1; x2=x1; x1=x; y2=y1; y1=y; } x=x2; y=y2; return a; } Замечание по поводу использования внешних переменных x и y.

>Лекция  26.09.11г. 42 Создание отдельных модулей Обе функции: euclid(a,b) и e_euclid(a,b) можно записать Лекция 26.09.11г. 42 Создание отдельных модулей Обе функции: euclid(a,b) и e_euclid(a,b) можно записать в отдельные файлы и компилировать независимо. В этом случае основная программа, которая и решает поставленную задачу, также размещается в отдельном файле и уже не содержит определений функций euclid(a,b) и e_euclid(a,b), а только лишь их объявления.

>Лекция  26.09.11г. 43 Пример программы с модульной структурой #include <stdio.h> #include <stdlib.h> #include Лекция 26.09.11г. 43 Пример программы с модульной структурой #include #include #include int x, y; int euclid(int, int); int e_euclid(int, int); int main() { int a, b, c, g, u, v, t; int x_max, y_max; printf("Input a, b, c: "); scanf("%d%d%d", &a, &b, &c); printf("Input x_max, y_max: "); scanf("%d%d", &x_max, &y_max); if (c % euclid(a, b)) printf("***no solution\n"); else { g = e_euclid(a, b); for(t = -25; t <= 25; t++) { if (fabs(u = x*(c/g) - t*(b/g)) > x_max) continue; if (fabs(v = y*(c/g) + t*(a/g)) > y_max) continue; printf("result: %d*(%d)+%d*(%d)=%d\n", a, u, b, v, c); } } system("PAUSE"); return 0; } объявления функций внешние переменные вызовы функций

>Лекция  26.09.11г. 44 Об использовании внешних переменных Алгоритм ЕЕ (без внешних переменных): int Лекция 26.09.11г. 44 Об использовании внешних переменных Алгоритм ЕЕ (без внешних переменных): int e_euclid(int a, int b, int *x, int *y) { int q, r, x1 = 0, x2 = 1, y1 = 1, y2 = 0; while (b) { q = a / b; r = a-q*b; a = b; b = r; *x = x2-q*x1; *y = y2-q*y1; x2=x1; x1=*x; y2=y1; y1=*y; } *x = x2; *y = y2; return a; }

>Лекция  26.09.11г. 45 Модифицированная программа #include <stdio.h> #include <stdlib.h> #include <math.h> int euclid(int, Лекция 26.09.11г. 45 Модифицированная программа #include #include #include int euclid(int, int); int e_euclid(int, int, int*, int*); int main() { int a, b, c, g, u, v, t; int x, y, x_max, y_max; printf("Input a, b, c: "); scanf("%d%d%d", &a, &b, &c); printf("Input x_max, y_max: "); scanf("%d%d", &x_max, &y_max); if (c % euclid(a, b)) printf("***no solution\n"); else { g = e_euclid(a, b, &x, &y); for(t = -25; t <= 25; t++) { if (fabs(u = x*(c/g) - t*(b/g)) > x_max) continue; if (fabs(v = y*(c/g) + t*(a/g)) > y_max) continue; printf("result: %d*(%d)+%d*(%d)=%d\n", a, u, b, v, c); } } system("PAUSE"); return 0; } объявления функций вызовы функций