[Закрыть]
 
popoff.donetsk.ua
Заниматься с успехом можно только тем, что любишь.
Начало | Новости | Статьи | Форум | Опросы | Карта сайта | Обо мне
popoff.donetsk.ua - Статьи - Программирование - Технологии программирования - Флаги и оператор GOTO - Угадайте, что делает эта программа
Я это делаю
Персональное меню
Голосование
Деньги, либо любимое занятие? Постоянный адрес этого вопроса
Ваш возраст (не обязательно):

Введите целое число от 3 до 99.
Почему? (не обязательно):
Другие вопросы
Поиск по сайту
Реклама
Гинеколог, стоматолог, психотерапевт в Донецке
Статистика

Угадайте, что делает эта программа

Постоянный адрес статьи

Вот пример программы без единого GOTO, наваянной на языке Си.

void some_function(int *a,int n,int b)
{
  int i=n-1;
  int is_exit=0;
  int is_notfound=0;
  while(is_exit==0)
  {
    if(i>=0)
    {
      if(a[i]==b)
      {
        a[i]++;
        is_exit=1;
      }
      else
      {
        is_notfound=1;
        i--;
      }
      if((is_notfound==1)&&(is_exit==1))
      {
        a[i]++;
      }
    }
    else
    {
      is_exit=1;
    }
  }
}

Сколько времени Вам потребуется, чтобы понять смысл фигурирующего здесь цикла while?

Отмечу достаточно типичное неумение пользоваться логическими выражениями и незнание приоритетов логических операций: if((is_notfound==1)&&(is_exit==1)) вместо if(is_notfound&&is_exit)

А вот эквивалентная функция, полученная тождественными преобразованиями:

void some_function(int *a,int n,int b)
{
  int i;
  int k;

  if(n>=0)
  {
    k=-1;
    for(i=n-1;i>=0&&k<0;i--)
      if(a[i]==b) k=i;
    if(k>=0)
      a[k]++;
    else
      a[0]++;
  }
}

Здесь сразу видно, что делает эта функция: она ищет последнее вхождение элемента b в массиве a и увеличивает его на 1. Если таких элементов нет, то увеличивает самый первый элемент.

Оператор if нужен для того, чтобы ничего не делать, если в массиве нет ни одного элемента.

А теперь представьте себе, что вам нужно модифицировать эту программу под новую задачу: очевидно, что во втором случае это сделать не только намного легче, но и минимален риск внести при исправлении ошибку.

Именно в этом и заключается цель применения структурного программирования.

Впрочем, польза от механического исключения GOTO есть: по крайней мере, так можно доказать, что без GOTO можно обойтись в любых программах.

Если подумать, второй вариант функции можно было бы упростить. Хорошо ли так писать, или плохо, я не знаю. Видимо, оптимальным было бы использование некоторой комбинации.

void some_function(int *a,int n,int b)
{
  int i;
  int k;

  if(n<0) return;

  k=0;
  for(i=n-1;i>0&&!k;i--)
    if(a[i]==b) k=i;
  a[k]++;
}

Кстати, в первом варианте программы содержится ошибка. Она делает не совсем то, что от нее требуется. Раз уж со смыслом я Вам помог, то попробуйте теперь отыскать и исправить эту ошибку.

Смотрите также

Прототип этого примера:
http://www.inr.ac.ru/~info21/blackbox/disciplina/primerbezgoto.htm

Последняя модификация: 13.11.05 19:52

Обсуждение статьи в форуме

Не проходите мимо! Оставьте Ваш комментарий в форуме! >>>

07.04.12 12:26 Gro

В обеих модифицированных функциях допускается модификация массива нулевой длины, что является ошибкой.
В первой это ошибка содержится в условии if ( n >= 0 ), во второй - в операторе if ( n < 0 ) return;

Переменная k является излишней.

if ( n > 0 )
  {
    for( i = n - 1; i && ( a[ i ] != b ); --i )
      ;

    

++a[ i ];
  }

Заменив for на более наглядный while, получаем

if ( n > 0 )
  {
    i = n - 1;

    

while( i && ( a[ i ] != b ) )
      --i;

    

++a[ i ];
  }

Более эффективная реализация использует указатель на элемент массива

int* p;

if ( n > 0 )
  {
    for(
      p = a + n; /* p установлен на один элемент за конец массива, законно */
      ( p > a ) && ( *( --p /* NB: декремент! */ ) != b );
      /* пусто */
    )
      ;

    

++( *p );
  }

или, с while вместо for

int* p;

if ( n > 0 )
  {
    p = a + n; /* p установлен на один элемент за конец массива, законно */

    

while(
      ( p > a ) &&
      ( *( --p /* NB: декремент! */ ) != b )
    )
      ;

    

++( *p );
  }

Даём переменным осмысленные имена и получаем эффективный удобочитаемый код (не забываем, что это C, а не C++)

void some_function( int* pnAr, int nElCount, int nVal )
  {
    int* pnEl;

    

if ( nElCount > 0 )
      {
        pnEl = pnAr + nElCount; /* pnEl установлен на один элемент за конец массива, законно */

        

while(
          ( pnEl > pnAr ) &&
          ( *( --pnEl /* NB: декремент! */ ) != nVal )
        )
          ;

        

++( *pnEl );
      }
  }

При перепечатке ссылка на автора обязательна. Gromolyak (dima@amsd.com, gromolyak@bk.ru)

Просмотреть все комментарии в режиме форума. Всего комментариев: 1
Не проходите мимо! Оставьте Ваш комментарий в форуме! >>>