Advertisement
Guest User

Untitled

a guest
Oct 6th, 2020
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.38 KB | None | 0 0
  1. Вы уже познакомились с базовыми алгоритмическими конструкциями, такими как ветвление, цикл и т.п. В этом уроке поговорим про алгоритмизацию. Такие же конструкции встречаются и в большинстве высокоуровневых языков программирования, в том числе и в языке С.
  2. Управляющий оператор if
  3. Простая форма оператора if
  4. Оператор if — управляющий оператор языка С, реализующий ветвление алгоритма.
  5. if (выражение)
  6. оператор1;
  7. или
  8. if (выражение)
  9. {
  10. оператор1;
  11. оператор2;
  12. }
  13.  
  14.  
  15.  
  16.  
  17.  
  18. Если выражение в скобках истинно, то оператор выполняется, в противном случае — пропускается. Оператор может быть простым или составным (блоком, выделенным с обеих сторон {}). Круглые скобки вокруг выражения обязательны.
  19.  
  20. Примеры:
  21. if (x > max)
  22. max = x;
  23. if (x < min || x > max)
  24. {
  25. max *= 2;
  26. min /= 2;
  27. }
  28.  
  29. Полная форма оператора if
  30. if (выражение)
  31. оператор1;
  32. else
  33. оператор2;
  34.  
  35.  
  36.  
  37.  
  38. Если выражение в скобках истинно, то оператор1 выполняется, а оператор2 пропускается. Если выражение ложно, пропускается оператор1, а выполняется оператор2. оператор1 и оператор2 могут быть простыми или блоками. Скобки вокруг выражения, следующего за ключевым словом if, обязательны.
  39.  
  40. Пример:
  41. ​​​​​​​if (x != 0)
  42. {
  43. y /= x;
  44. }
  45. else
  46. {
  47. y = 0;
  48. }
  49. Возможны серии вложенных операторов if-else (как и любых других управляющих операторов, перечисленных далее), однако такая запись является не самой предпочтительной, так как ее сложно воспринимать человеческому глазу. При использовании вложенных операторов if-else, else связывается с ближайшим if.
  50. if (c > ' ')
  51. if ( c >= '0' && c <= '9')
  52. ++digits;
  53. else
  54. ++non_digits;
  55.  
  56. ВАЖНО
  57. Помните, что любой код пишется и поддерживается человеком,
  58. поэтому старайтесь писать такой код, который легко
  59. поддерживать и читать. Вместо вложенного if-else можно
  60. воспользоваться управляющим оператором switch
  61. Оператор switch
  62. Оператор switch — управляющий оператор языка С, реализующий алгоритмическую структуру выбор.
  63.  
  64. Синтаксис оператора switch определен следующим образом:
  65. switch (выражение)
  66. {
  67. case const1: оператор;
  68. case const2: оператор;
  69. . . .
  70. default: оператор;
  71. }
  72.  
  73. ​​​​​​​
  74.  
  75. Выражение в скобках должно быть целого типа (можно использовать символьные константы, так как их тип целый). Выражение вычисляется и сравнивается с различными константами, записанными после ключевого слова case. Допускается использование констант целого или символьного типа или константное выражение указанных типов (например, 5, 'a', 2048/512). Если подходящая константа найдена, вычисления продолжаются с оператора, следующего за словом case, соответствующим этой константе. Затем выполняются все последующие операторы вплоть до появления оператора break или завершающей оператор switch скобки }. Метки case могут располагаться в любом порядке, но значения соответствующих констант должны быть различными.
  76.  
  77. switch, case, default и break — ключевые слова. Оператор break вызывает немедленный выход из оператора switch.
  78.  
  79. Метка default может отсутствовать. Если же она есть и среди указанных констант не найдено подходящей, управление передается операторам, следующим за меткой default. Если default отсутствует и среди указанных констант не найдено подходящей, оператор switch пропускается.
  80.  
  81. Если значение в операторе switch совпадает с одной из констант, вычисления продолжаются после соответствующей метки. Последующие операторы выполняются до тех пор, пока не встретится оператор break, независимо от того, предшествуют этим операторам какие-либо метки case. Говорят, что выполнение «проваливается», если не встретился оператор break. Распространенная ошибка состоит в пропуске оператора break, когда необходим выход из оператора switch.
  82.  
  83. Пример:
  84. switch(x)
  85. {
  86. case ‘a’:
  87. case ‘A’:
  88. y *= 5;
  89. break;
  90. case ‘b’:
  91. case ‘B’:
  92. y /= 3;
  93. break;
  94. default:
  95. y = 0;
  96. }
  97. Когда требуется использовать оператор switch, а когда конструкцию if-else? Нельзя применять оператор switch, когда выбор вариантов основан на вычислении значения переменной или выражения вещественного типа. Удобного способа применить оператор switch в случае, когда возможные значения переменной попадают в некоторый диапазон, также не существует. Проще написать, например, так:
  98. ​​​​​​​if (x < 1000 && x > 2)
  99. При замене этой строки оператором switch придется ввести в программу метки для всех целых чисел от 3 до 999. Тем не менее, если есть возможность использования оператора switch, ею надо воспользоваться, если это позволит воспринимать код более удобно.
  100. Оператор цикла while
  101. Оператор цикла while — управляющий оператор языка С, реализующий выполнение цикла-пока в алгоритме. Синтаксис оператора цикла while определяется следующим образом:
  102. while (выражение)
  103. оператор;
  104. или
  105. while (выражение)
  106. {
  107. оператор;
  108. }
  109.  
  110.  
  111.  
  112.  
  113. Вычисляется выражение; если оно истинно (ненулевое), выполняется оператор. Выражение вычисляется снова и, если оно остается истинным, снова выполняется оператор, и т.д. Если выражение ложно, происходит выход из цикла. Как правило, значение выражения изменяется в результате выполнения некоторых действий в цикле. Оператор в цикле while выполняется 0 или более раз. Оператор может быть простым или составным (блоком). Частный случай простого оператора — пустой оператор.
  114.  
  115. Примеры:
  116. size_t i = 1;
  117. while (i <= 5)
  118. {
  119. ++i;
  120. }
  121. size_t x = 0;
  122. size_t y = 10;
  123. while (x++ != y--)
  124. ; // нулевое выражение
  125. Оператор цикла do-while
  126. Оператор цикла do-while — управляющий оператор языка С, реализующий выполнение цикла-до в алгоритме.
  127. Синтаксис оператора цикла do-while определяется следующим образом:
  128. ​​​​​​​do
  129. оператор;
  130. while (выражение);
  131. или
  132. ​​​​​​​do
  133. {
  134. оператор;
  135. }
  136. while (выражение);
  137. Цикл do-while похож на цикл while за исключением того, что значение выражения проверяется после выполнения оператора. Поэтому тело цикла выполняется как минимум один раз. Если значение выражения истинно, тело цикла выполняется повторно, выражение вновь вычисляется и т.д., до тех пор пока значение выражения не станет ложным. Оператор может быть как простым, так и составным.
  138.  
  139. Пример:
  140. size_t num = 2;
  141. size_t pow = 5;
  142.  
  143. do
  144. {
  145. num *= num;
  146. --pow;
  147. }
  148. while (pow > 0);
  149. Оператор цикла for
  150. Оператор цикла for — управляющий оператор языка С, реализующий выполнение цикла «для» в алгоритме. Этот оператор очень удобен для представления счетных циклов, однако он может использоваться и для итерационных и поисковых циклов. Синтаксис оператора цикла for определяется следующим образом:
  151. for (выражение1; выражение2; выражение3)
  152. оператор;
  153. ​​​​​​​
  154.  
  155. Цикл for используется для описания определенных действий для инициализации переменных цикла, циклического повторения тела цикла и изменения значений его переменных.
  156.  
  157. выражение2 цикла for всегда используется в качестве условия его окончания.
  158.  
  159. выражение1 часто применяется для инициализации переменных, а выражение3 для их изменения.
  160.  
  161. выражение1 вычисляется один раз при входе в цикл; выражение2 используется многократно как условие окончания; выражение3 вычисляется многократно после выполнения операторов тела цикла.
  162.  
  163. Оператор for эквивалентен следующей последовательности операторов:
  164. выражение1;
  165. while (выражение2)
  166. {
  167. оператор;
  168. выражение3;
  169. }
  170. Преимущество синтаксиса оператора цикла for по сравнению с синтаксисом оператора цикла while заключается в том, что управляющие выражения цикла собраны вместе, что повышает удобочитаемость программы.
  171.  
  172. Пример:
  173. size_t pow = 0;
  174.  
  175. for (size_t num = 1024; num > 0; num /= 2)
  176. ++pow;
  177. Операторы break и continue
  178. Операторы break и continue являются операторами передачи управления, не входящими в число базовых алгоритмических структур, на основании которых строятся структурные программы. Однако они используются достаточно часто.
  179.  
  180. Управляющий оператор break осуществляет немедленный выход из циклов while, do-while и for. Одиночный оператор break не может использоваться для выхода из более чем одного уровня вложения циклов. Оператор break может использоваться и для выхода из оператора switch.
  181.  
  182. Управляющий оператор continue осуществляет прекращение выполнения текущей итерации цикла, вызывая немедленное выполнение следующей итерации. Оператор continue используется только внутри циклов. Управление передается на управляющую часть (заголовок) цикла, с пропуском оставшихся операторов тела цикла.
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190. Оператор goto
  191. Управляющий оператор goto вызывает безусловный переход управления на выполнение оператора, перед которым указана соответствующая метка.
  192. ​​​​​​​goto метка;
  193. Метка (label) — это идентификатор, завершаемый двоеточием, который помечает оператор.
  194. ​​​​​​​метка: оператор;
  195. Метки видны только внутри своей функции (о функциях поговорим далее).
  196. Часто говорят, что структурное программирование — это программирование без goto. Строго говоря, в этом операторе нет никакой необходимости. Оператор goto можно использовать только для выхода из глубоко вложенных циклов. В противном случае использование goto делает структуру программы запутанной и трудной для отладки. На использование оператора goto провоцирует плохо продуманный алгоритм.
  197.  
  198. Пример:
  199. // goto можно использовать, чтобы легко выйти из многоуровневого цикла
  200. for (int x = 0; x < 3; ++x)
  201. {
  202. for (int y = 0; y < 3; ++y)
  203. {
  204. if (x + y >= 3)
  205. goto endloop;
  206. }
  207. }
  208. endloop:;
  209. Функции
  210. Функция — это именованный фрагмент программы. Данные могут передаваться в функцию и функция может возвращать данные. Функция состоит из составного оператора (тела функции) и идентификатора (имени функции).
  211. // Определение функции.
  212. // Определяет функцию с именем “sum” и телом “{ return x+y; }”
  213. int sum(int x, int y)
  214. {
  215. return x + y;
  216. }
  217. Функция может принимать 0 или более параметров, которые инициализируются из аргументов оператора вызова функции, и может возвращать значение в блок ее вызова с помощью оператора return.
  218. int n = sum(1, 2); // параметры x и y инициализируются аргументами 1 и 2
  219. ВАЖНО
  220. Комбинацию из имени функции, списка аргументов и возвращаемого\
  221. значения называют прототипом функции
  222. Тело функции предоставляется в определении функции. Каждая функция должна быть определена только 1 раз на всю программу, если только она не является inline-функцией.
  223.  
  224. Вложенные функции по стандарту недопустимы.
  225. ВАЖНО
  226. ​​​​​​​Функции не имеют доступа к локальным переменным из области ее вызова.
  227. Переданные аргументы по факту являются копиями этих локальных переменных, то есть не зависят от них.
  228. Объявление функции
  229. Объявление функции используется для предоставления информации об имени функции, типе возвращаемого значения и списка аргументов в текущей области видимости. Это крайне полезно для модульной структуризации программы, так как любая вызывающая функция должна быть проинформирована о виде вызываемой функции (то есть, должна знать ее прототип).
  230. Объявление может быть сделано перед вызывающей функцией или внутри ее.
  231.  
  232. Например, объявление функции sum, определенной выше, будет выглядеть так:
  233. ​​​​​​​int sum(int x, int y);
  234. Имея такую запись в текущем файле и определение — в другом, можно осуществлять вызов функции.
  235.  
  236. Возможно, сейчас это кажется немного избыточным, но на практике будет понятно, почему это удобно.
  237. Назначение стека при вызове функции
  238. Стек — это область памяти, используемая выполняемой программой для временного запоминания значений.
  239. При вызове функции происходит следующее:
  240. Все значения передаваемых аргументов функции помещаются на стек. Затем запоминаются значения существенных регистров
  241. Управление передается вызванной функции. Значения аргументов связываются с соответствующими областями памяти на стеке, выделенными под формальные параметры, указанные в прототипе функции
  242. Затем определяется расположение на стеке для локальных переменных
  243. Этот набор параметров, регистров и автоматических переменных для вызова функции называется кадром (frame). Если вызванная функция выполняет вызов другой функции, на стек помещается еще один кадр. Только один кадр является активным в любой момент времени. Активная часть стека «растет» при вызове функции и «сокращается» при выходе из функции. Стековое пространство все время повторно используется, и это является причиной того, почему автоматические переменные имеют до инициализации неопределенные значения. Они зависят от того, какие значения запоминались в соответствующем месте памяти до данного вызова функции.
  244.  
  245. Проще рассмотреть этот механизм на примере.
  246. float g(double val)
  247. {
  248. int count;
  249. . . .
  250. }
  251.  
  252. int f(int x, int sum)
  253. {
  254. double total;
  255. g(20.5);
  256. . . .
  257. }
  258.  
  259. int main()
  260. {
  261. int x = 10;
  262. int y = 100;
  263. f(5, 10);
  264. . . .
  265. }
  266.  
  267.  
  268.  
  269.  
  270. Оператор return
  271. Функция может передавать одно значение обратно в вызывающую функцию. Тип возвращаемого значения определяется в определении прототипа функции и объявляется в объявлении прототипа функции.
  272.  
  273. Оператора возврата return — оператор, с помощью которого функция возвращает значение в вызывающую функцию. Синтаксис оператора возврата return:
  274. return [выражение];
  275. При выходе на оператор return выполняется возврат из функции так, что управление вновь передается в вызывающую функцию на оператор, следующий за вызовом. В случае если оператор return имеет выражение, значением вызова функции является значение этого выражения. Если оператор return не имеет выражения, значение вызова функции не определено.
  276. Функция может иметь более одного оператора return.
  277.  
  278. Примеры:
  279. ​​​​​​​int func1(void)
  280. {
  281. ...
  282. if (n==0 || n==1)
  283. return 1;
  284. else
  285. return 0;
  286. }
  287. Функция func1() возвращает значение целого типа.
  288. void func2(void)
  289. {
  290. ...
  291. return;
  292. }
  293. Функция func2() не возвращает никакого значения.
  294. Рекурсивные функции
  295. Функция в языке программирования С может быть рекурсивной, т.е. может вызывать сама себя. Каждый раз, когда функция вызывает себя, на стек помещается новый кадр. Функция должна вызывать себя условно, например, внутри оператора if, иначе бесконечная рекурсия переполнит стек.
  296.  
  297. Следующий пример позволяет вычислить факториал числа 5, используя рекурсию:
  298. ​​​​​​​int factorial(int num);
  299. int main()
  300. {
  301. int num = 5;
  302. int fact = factorial(num);
  303. }
  304.  
  305. int factorial(int num)
  306. {
  307. if (num == 0)
  308. {
  309. return 0;
  310. }
  311. else if (num == 1)
  312. {
  313. return 1;
  314. }
  315. else
  316. {
  317. return num * factorial(num - 1);
  318. }
  319. }
  320. Точки входа / выхода программы
  321. Каждая программа на С начинает свое выполнение из функции с именем main, которая либо завершается, либо вызывает другие функции. Выйдя из функции main, программа завершается. Функция main вызывается операционной системой в тот момент, когда пользователь запускает программу.
  322. int main (void) { body }
  323. int main (int argc, char *argv[]) { body }
  324.  
  325. У функции main есть свои параметры, инициализируемые ОС при старте:
  326. argc — неотрицательное значение, отражающее количество аргументов, переданное программе из того окружения, в котором она запущена.
  327. argv — список переданных аргументов, начиная с имени программы.
  328. ​​​​​​​
  329.  
  330. Мы с вами изучили новые операторы и функции! Теперь вы понимаете, как реализовывать функцию, знаете базовые блоки алгоритмов и структуру программы. Давайте перейдем к заданиям!
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement