КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Использование goto. 2 страница
/* Зенон */ #define LIMIT 15 main () { int count; float sum, x; for (sum = 0.0, x = 1.0, count = 1; count <= LIMIT; count++, x *= 2.0) { sum + = 1.0/x; printf("sum = %f когда count = %d.\n", sum, count); } }
В результате выполнения программы получим значения сумм, соответствующих первым 15 членам ряда:
Можно видеть, что, хотя мы и добавляем новые члены, сумма, по-видимому, стремится к какому-то пределу. И действительно, математики показали, что при стремлении числа членов к бесконечности сумма ряда сходится к 2,0, что и демонстрируется нашей программой.
11.1.4. Сравнение циклов. После того как вы решили, что вам необходимо использовать оператор цикла, возникает вопрос: циклом какого вида лучше всего воспользоваться? Во-первых, решите, нужен ли вам цикл с предусловием или же с постусловием. Чаще вам нужен будет цикл с предусловием. По оценкам Кернигана и Ритчи, в среднем циклы с постусловием (do while) составляют только 5% общего числа используемых циклов. Существует несколько причин, по которым программисты предпочитают пользоваться циклами с предусловием; в их числе один общий принцип, согласно которому лучше посмотреть, куда вы прыгаете, до прыжка, а не после. Вторым моментом является то, что программу легче читать, если проверяемое условие находится в начале цикла. И наконец, во многих случаях важно, чтобы тело цикла игнорировалось полностью, если условие вначале не выполняется. Для превращения цикла while в цикл for необходимо предварительно осуществить инициализацию некоторых выбранных переменных и включить в тело цикла операторы, корректирующие их значения:
инициализация; while (проверка условия) { тело; коррекция; }
Данная запись по своим функциональным возможностям эквивалентна следующей:
for(инициализация; проверка условия, коррекция) тело;
Исходя из соображений стиля программирования, применение цикла for представляется более предпочтительным в случае, когда в цикле используется инициализация и коррекция переменной, а применение цикла while — в случае, когда этого нет. Поэтому использование цикла while вполне оправданно в случае
while((ch = getchar())!= EOF)
Применение цикла for представляется более естественным в случаях, когда в циклах осуществляется счет прохождений с обновлением индекса:
for(count = 1; count <= 100; count ++)
11.1.5. Вложенные циклы. Вложенным называется цикл, находящийся внутри другого цикла. Начнем с программы, проверяющей делимость одного числа; в ней имеется всего один оператор цикла.
/* простое число1 */ main() { int number, divisor; printf(" О каком числе вы хотите знать, простое ли оно?\n"); scanf(" %d", &number); /* получение ответа */ while (number < 2) /* число отвергается */ { printf(" Извините, мы не принимаем чисел меньше 2.\n"); printf(" Пожалуйста, попробуйте еще раз.\n"); scanf(" %d", &number); } for (divisor = 2; number % divisor!= 0; divisor ++) ; /* проверка, простое число или нет, осуществляется внутри спецификации цикла */ if (divisor = = number) /* выполняется после завершения цикла */ printf(" %d — простое число.\n", number); else printf(" %d — не простое число\n", number); }
Мы воспользовались структурой цикла while, чтобы избежать ввода значений, которые могли бы привести к аварийному завершению программы. Обратите внимание, что все вычисления выполняются внутри спецификации цикла for. Величина переменной number последовательно делится на возрастающие значения делителей до тех пор, пока не произойдет деление нацело (т. е. number % divisor станет равным 0). Если первым делителем, который приведет к такому результату окажется само это число, то значение переменной number — простое число. В противном случае данное число будет иметь меньший делитель, и это приведет к тому, что цикл завершится раньше. Для нахождения всех простых чисел, меньших некоторой задан-ной величины, нам нужно будет заключить наш цикл for в некоторый другой цикл. На псевдокоде это будет выглядеть следующим образом:
для числа (number) = 1 до верхнего предела limit проверять, является ли число простым
Вторая строка представляет собой нашу предыдущую программу. Переводя эту запись на язык Си, получим_программу:
/* простые числа2 */ main() { int number, divisor, limit; int count = 0; printf(" Укажите, пожалуйста, верхний предел для поиска простых чисел.\n"); printf(" Верхний предел должен быть 2 или больше.\n"); scanf(" %d", &limit); while(limit < 2) /* вторая попытка, если ошибка при вводе */ { printf(" Вы были невнимательны! Попробуйте еще раз.\n"); scanf(" %d", &limit); } printf(" Сейчас будут печататься простые числа!\n"); for (number = 2; number < = limit; number++) /* внешний цикл */ { for (divisor =2; number % divisor!= 0; divisor++) ; if(divisor = = number) { printf(" %5d", number); if (++count % 10 = = 0) printf(" \n"); /* новая строка начинается через каждые 10 простых чисел */ } } printf(" \n Вот и все!\n"); }
Во внешнем цикле каждое число, начиная с 2 и кончая величиной limit, последовательно берется для проверки. Указанная проверка осуществляется во внутреннем цикле. Мы использовали переменную count для хранения счетчика получаемых простых чисел. При печати каждое одиннадцатое простое число мы начинаем с новой строки. Ниже приводится пример результатов, получаемых с помощью такой программы:
Этот способ решения довольно прост, но он не является самым эффективным. Например, если вы хотите узнать, является ли число 121 простым или нет, нет необходимости проверять, существуют ли у него делители, превышающие 11. Дело в том, что если у данного числа существует делитель, больший 11, то результатом деления будет число, меньшее 11; тогда этот делитель был бы обнаружен раньше. Поэтому требуется проверять только делители, не превышающие величину квадратного корня из числа, но в данном случае программа будет несколько сложнее. 11.1.6. Алгоритмы и псевдокод. А теперь вернемся к нашей «тупоумной» программе, угадывающей число. Недостаток этой программы кроется не в программировании самом по себе, а в «алгоритме», т. е. методе, используемом для отгадывания числа. Этот метод можно описать следующим образом:
попросите пользователя задумать число компьютер начинает угадывание с 1 до тех пор пока догадка неверна, предлагаемое значение увеличивается на 1
Эта запись, между прочим, служит примером «псевдокода», представляющего собой способ выражения смысла программ на упрощенном языке и являющегося некоторым аналогом языка машины. Псевдокод очень эффективен при разработке логики программы. Если мы хотим улучшить программу, нам в первую очередь необходимо улучшить алгоритм. Один из методов заключается в том, чтобы выбрать число где-нибудь посередине между 1 и 100 (число 50 нам вполне подходит) и попросить пользователя ответить, больше ли это число задуманного, меньше его или равно ему. Если он сообщает, что данное число слишком велико, то тем самым из рассмотрения немедленно исключаются все числа между 50 и 100. Следующей догадкой программы является число, выбранное где-то посередине между 1 и 49. И снова ответ на вопрос, велико или мало это число, позволит исключить из рассмотрения половину оставшихся возможных чисел; программа продолжает указанный процесс, быстро сужая поле поиска до тех пор, пока задуманное число не будет угадано. Давайте запишем эти логические рассуждения на псевдокоде. Пусть highest — максимально возможная величина отгадываемого числа, a lowest — его минимально возможное значение. Вначале этими величинами будут соответственно 100 и 1, поэтому алгоритм запишется следующим образом:
установить highest равным 100 установить lowest равным 1 попросить пользователя задумать число предложенное значение (guess) равно (highest + lowest)/2 пока догадка неверна, делать следующее:
{если предложенное значение велико, установить highest равным этому предложенному значению минус 1 если предложенное значение мало, установить lowest равным этому предложенному значению плюс 1 новое предложенное значение равно (highest + lowest)/2} Обратите внимание на логику алгоритма: если предложенное значение, равное 50, велико, то максимально возможная величина задуманного числа будет равна 49. Если же значение 50 мало, то минимально возможная величина числа будет равна 51. Сейчас мы переведем текст, указанный выше, на язык Си. Полученная программа представлена ниже.
/* угадывание числа2 */ /* более эффективный способ угадывания */ #include <stdio.h> #define HIGH 100 #define LOW 1 main() { int guess = (HIGH + LOW)/2; int highest = HIGH; int lowest = LOW; char response; printf(" Задумайте число от %d до %d. Я попробую", LOW, HIGH); printf(" угадать его.\n Отвечайте д, если моя догадка правильна,"); printf(" б, если \n больше, и м, если"); printf(" меньше. \n); printf("Итак... ваше число %d?\n", guess); while((response = getchar())!= 'д') { if(response!= ' \n') { if (response == ' 6') {/* уменьшение верхнего предела. Если предло- женное значение слишком велико */ highest = guess - 1; guess = (highest + lowest)/2; printf(" Гм... слишком велико. Ваше число %d?\n", guess); } else if (response == ' м') {/* увеличение нижнего предела, если предложенное значение слишком мало */ lowest = guess + 1; guess = (highest + lowest)/2; printf('Гм... слишком мало. Ваше число %d?\n", guess); } else {/* подводите пользователя к правильному ответу */ printf("Я не понимаю; введите, пожалуйста, д, б"); printf(" или м.\n"); } } printf("Я знала, что смогу сделать это!\n"); }
11.2. Оператор break. В С оператор break может использоваться для выхода из некоторого цикла до того, как условие проверки получит значение ЛОЖЬ. Во многом оператор break похож на оператор goto; различие в том, что точка перехода точно не известна. При выходе из цикла по команде break программа продолжается с оператора, следующего за циклом. Взгляните на очень простой пример:
/*07BREAK.C Программа на С, иллюстрирующая использование оператора break*/
#include "stdafx.h" #include <iostream> #include <conio.h> #include <stdio.h> #include <process.h> using namespace std; main () { int itimes = 1, isum = 0; while(itimes < 10){ isum += isum + itimes; if(isum > 20) break; itimes++; } printf ("\n\nPress any key to finish\n"); /* Конец работы */ _getch(); return(0); } Бывает, что break используется для выхода из цикла в тех случаях, когда заданы два разных условия прекращения его работы. Ниже приводится цикл, реализующий эхо-печать символов и завершающийся при чтении либо признака EOF, либо символа «новая строка».
11.3. Оператор continue. В С существует небольшое различие между операторами break и continue. Как вы уже видели в последнем примере, break полностью прекращает выполнение цикла. В отличие от этого, оператор continue приводит к игнорированию всех следующих за ним операторов, однако не препятствует инкременту переменной управления циклом или выполнению проверки условия продолжения цикла. Другими словами: если переменная управления циклом продолжает отвечать условию выполнения цикла, то цикл повторяется. Эта мысль иллюстрируется следующей программой, представляющей собой игру "угадай число":
/*07CONTNU.C Программа на С, иллюстрирующая использование оператора continue*/
#include "stdafx.h" #include <iostream> #include <conio.h> #include <stdio.h> #include <process.h> using namespace std; #define TRUE 1 #define FALSE 0 main() { int ilucky_number=77, iinput_val, inumber_of_tries=0, iam_lucky=FALSE; while(!iam_lucky){ /* Введите предполагаемое число: */ printf("Please enter your lucky guess: "); scanf("%d",&iinput_val); inumber_of_tries++; if(iinput_val == ilucky_number) iam_lucky=TRUE; else continue; /* Для угадывания вам понадобилось всего... попыток! */ printf("It only took you %d tries to get lucky!", inumber_of_tries); } printf ("\n\nPress any key to finish\n"); _getch(); return(0); }
Этот оператор может использоваться во всех трех типах циклов, но не в операторе switch.
11.4. Совместное использование операторов break и continue. Операторы break и continue можно использовать вместе для решения некоторых интересных задач программирования. Посмотрите на следующий пример на C++:
// 07BRACNTG.CPP // Программа на C++, показывающая преимущества от совместного // использования операторов break и continue
#include "stdafx.h" #include <iostream> #include <conio.h> #include <stdio.h> #include <process.h> #include <ctype.h> using namespace std; #define NEWLINE '\n' main () { int c; while((c=getchar())!= EOF) { if (isascii(c) == 0) { cout << "Not an ASCII character; "; // He ASCII-символ; cout << "not going to continue/n"; // продолжения нет break; } if(ispunct(c) || isspace(c)) { putchar(NEWLINE); continue; } if (isprint(c) == 0) { c = getchar(); continue; } putchar(c); } printf ("\n\nPress any key to finish\n"); _getch(); return(0); } До того, как рассмотреть принцип работы этой программы, взгляните на ее входные значения:
word control ^В exclamation' apostrophe' period. ^Z
Также посмотрите на символы, полученные на выходе:
word control В exclamation apostrophe period
Программа считывает символы до тех пор, пока не введен символ EOF (end-of-file — конец файла) ^Z. Затем введенные символы анализируются: удаляются все непечатаемые символы и каждое "слово" помещается на отдельной строке. Для этого используются некоторые очень интересные функции, описанные в файле ctype.h, в том числе isascii(), ispunct(), isspace() и isprint(). Каждой функции в качестве параметра передается символ, а возвращается ноль или некоторое другое значение, показывающее результат сравнения. Функция isascii() показывает, относится ли указанный символ к набору допустимых ASCII-символов; функция ispunct() — является ли символ знаком пунктуации; функция isspace() — не является ли этот символ пробелом; и наконец функция isprint() — относится ли он к печатаемым символам. Используя эти функции, программа определяет, продолжать ли выполнение и, если продолжать, то, что необходимо делать с каждым введенным символом.
11.5. Оператор goto. Оператор goto — одно из важнейших средств Бейсика и Фортрана — также реализован и в Си. Однако на этом языке в отличие от двух других можно программировать, совершенно не используя указанное средство. Керниган и Ритчи считают оператор goto «чрезвычайно плохим» средством и предлагают «применять его как можно реже или не применять совсем». Оператор goto состоит из двух частей — ключевого слова goto и имени метки. Имена меток образуются по тем же правилам, что и имена переменных. Приведем пример записи оператора
goto part2;
Чтобы этот оператор выполнился правильно, необходимо наличие другого оператора, имеющего метку part2; в этом случае запись оператора начинается с метки, за которой следует двоеточие.
part2: printf(" Уточненный анализ:\n");
11.5.1. Использование goto. В принципе вы никогда не обязаны пользоваться оператором goto при программировании на Си. Но если ваш предыдущий опыт связан с работой на Фортране или Бейсике, в каждом из которых требуется его использовать, то у вас могли выработаться навыки программирования, основанные на применении данного оператора. Чтобы помочь вам преодолеть эту привычку, ниже вкратце приводится несколько знакомых вам ситуаций, реализуемых с помощью goto, а затем показывается, как это можно осуществить другими средствами, в большей степени соответствующими духу языка Си.
1. Работа в ситуации, когда в операторе if требуется выполнить более одного оператора:
if (size > 12) goto a; goto b; a: cost = cost * 1.05; flag - 2; b: bill = cost * flag;
Обычный подход, применяемый в языке Си и заключающийся в использовании составного оператора, или блока, упрощает понимание смысла программы:
if (size > 12); { cost = cost * 1.05; flag = 2; } bill = cost * flag;
2. Осуществление выбора из двух вариантов:
if(size > 14) goto a; sheds = 2; goto b; a: sheds = 3; b: help = 2 * sheds;
Наличие в языке Си структуры if-else позволяет реализовать такой выбор более наглядно:
if(ibex > 14) sheds = 3; else sheds = 2; help = 2 * sheds;
3. Реализация бесконечного цикла:
readin: scanf(" %d", &score); if(score < 0) goto stage2; большое количество операторов; goto readin: stage2: дополнительная чепуха;
Эквивалентный фрагмент, в котором используется цикл while, выглядит так:
scanf("%d", &score); while(score > = 0) { большое количество операторов; scanf(" %d", &score); дополнительная чепуха;
4. Пропуск операторов до конца тела цикла: используйте оператор continue. 5. Выход из цикла: используйте оператор break.
11.6. Оператор exit(). В некоторых случаях программу необходимо закончить до того, как выполнились все ее операторы или условия. Для таких особых случаев в С имеется библиотечная функция exit(). Эта функция может иметь один целочисленный аргумент, называемый статусом. Операционные системы UNIX и MS-DOS интерпретируют значение статуса, равное нулю, как успешное завершение программы, а все ненулевые значения статуса говорят о различного вида ошибках. В следующей программе на C++ выполняется поиск среднего значения из списка, имеющего до 30 чисел. Выход из программы происходит, если пользователь просит усреднить большее, чем LIMIT, количество цифр.
// 07EXIT1.CPP // Программа на C++, иллюстрирующая использование функции exit
#include "stdafx.h" #include <iostream> #include <conio.h> #include <stdio.h> #include <process.h> #include <ctype.h> using namespace std; #define LIMIT 30 main() { int irow,irequested_qty,iscores[LIMIT]; float fsum=0,imax_score=0,imin_score=100, faverage; // Введите количество усредняемых величин: cout << "\nEnter the number of scores to be averaged: "; cin >> irequested_qty; if(irequested_qty > LIMIT) { // Вы можете задать только... чисел для усреднения, cout << "\nYou can only enter up to " << LIMIT << \ " scores" << " to be averaged.\n"; // Программа окончена. cout << "\n >>> Program was exited. <<<\n"; exit; } for(irow = 0; irow < irequested_qty; irow++) { // Введите число cout << "\nPlease enter a grade " << irow+1 << ": "; cin >> iscores[irow]; } for(irow = 0; irow < irequested_qty; irow++) fsum = fsum + iscores[irow]; faverage = fsum/(float)irequested_qty; for(irow = 0; irow < irequested_qty; irow++) { if(iscores[irow] > imax_score) imax_score = iscores[irow]; if(iscores[irow] < imin_score) imin_score = iscores[irow]; } cout << "\nThe maximum grade is " << imax_score; // Максимум cout << "\nThe minimum grade is " << imin_score; // Минимум cout << "\nThe average grade is " << faverage; // Среднее значение printf ("\n\nPress any key to finish\n"); _getch(); return(0); }
11.7. Оператор atexit(). Всякий раз, когда программа вызывает функцию exit() или происходит нормальное завершение программы, можно также вызывать любую зарегистрированную "функцию выхода", занесенную в atexit(). Следующая программа на С иллюстрирует эту возможность:
/*07ATEXIT.C Программа на С, показывающая зависимость между функцией atexit и порядком выполнения объявленных функций*/
#include "stdafx.h" #include <iostream> #include <conio.h> #include <stdio.h> #include <process.h> #include <ctype.h> #include <stdlib.h> using namespace std;
void atexit_fn1(void); void atexit_fn2(void); void atexit_fn3(void); main() { atexit(atexit_fn1); atexit(atexit_fn2); atexit(atexit_fn3); printf("Atexit program entered.\n"); /* Вход в программу Atexit.*/ printf("Atexit program exited.\n\n"); /* Выход из программы Atexit.*/ printf (">>>>>>>>>> <<<<<<<<,\n\n"); printf ("\n\nPress any key to finish\n"); _getch(); return(0); }
void atexit_fn1(void) { printf("atexit_fn1 entered.\n"); /* Вход в функцию atexit_fn1.*/ } void atexit_fn2(void) { printf("atexit_fn2 entered.\n"); /* Вход в функцию atexit_fn2.*/ } void atexit_fn3(void) { printf("atexit_fn3 entered.\n"); /* Вход в функцию atexit_fn3.*/ }
На выходе программы получается следующее:
Функция atexit() использует имя некоторой функции в качестве единственного параметра и регистрирует эту функцию как функцию выхода. Если программа завершается нормально, как в предыдущем примере, или она вызывает функцию exit(), то выполняются все функции, объявленные в atexit(). 12. Массивы. 12.1. Понятие массив. 12.2. Массивы в С. 12.3. Объявление массивов. 12.4. Проблема ввода. 12.5. Инициализация массивов.
Дата добавления: 2015-01-03; Просмотров: 660; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |