Читаем Программирование. Принципы и практика использования C++ Исправленное издание полностью

Здесь содержатся три очевидные ошибки. (Какие именно?) Кроме того, хороший тестировщик немедленно выявит возможности для переполнения при добавлении чисел к переменной sum.

  Многие циклы связаны с данными и могут вызвать переполнение при вводе больших чисел.

Широко известная и особенно опасная ошибка, связанная с циклами и заключающаяся в переполнении буфера, относится к категории ошибок, которые можно перехватить, систематически задавая два ключевых вопроса о циклах.

char buf[MAX];    // буфер фиксированного объема

char* read_line // опасная функция

{

  int i = 0;

  char ch;

  while(cin.get(ch) && ch!='\n') buf[i++] = ch;

  buf[i+1] = 0;

  return buf;

}

Разумеется, вы не написали бы ничего подобного! (А почему нет? Что плохого в функции read_line?) Однако эта ошибка, к сожалению, является довольно распространенной и имеет разные варианты.

// опасный фрагмент

gets(buf);       // считываем строку в переменную buf

scanf("%s",buf); // считываем строку в переменную buf

  Поищите описание функций gets и scanf в своей документации и избегайте их как чумы. Под словом “опасная” мы понимаем, что переполнение буфера является инструментом для взлома компьютеров. В настоящее время реализации выдают предупреждение об опасности использования функции gets и ее аналогов.

<p id="AutBody_Root521"><strong>26.3.3.4. Ветвление</strong></p>

  Очевидно, что, делая выбор, мы можем принять неправильное решение. Из-за этого инструкции if и switch являются одними из основных целей для тестировщиков. Существуют две проблемы, которые необходимо исследовать.

• Все ли возможные варианты предусмотрены?

• Правильные ли действия связаны с правильными вариантами выбора?

Рассмотрим следующую бессмысленную функцию:

void do_branch1(int x, int y) // плохая функция

    // неправильное использование инструкции if

{

  if (x<0) {

    if (y<0)

      cout << "Большое отрицательное число \n";

    else

      cout << "Отрицательное число \n";

  }

  else if (x>0) {

    if (y<0)

      cout << "Большое положительное число \n";

    else

      cout << "Положительное число \n";

  }

}

Наиболее очевидная ошибка в этом фрагменте заключается в том, что мы забыли о варианте, в котором переменная x равна нулю. Сравнивая числа (положительные или отрицательные) с нулем, программисты часто забывают о нем или приписывают неправильной ветви (например, относят его к отрицательным числам). Кроме того, существует более тонкая (хотя и распространенная) ошибка, скрытая в этом фрагменте: действия при условиях (x>0 && y<0) и (x>0 && y>=0) каким-то образом поменялись местами. Это часто случается, когда программисты пользуются командами “копировать и вставить”.

Чем более сложными являются варианты использования инструкций if, тем вероятнее становятся ошибки. Тестировщики анализируют такие коды и стараются не пропустить ни одной ветви. Для функции do_branch1 набор тестов очевиден.

do_branch1(–1,–1);

do_branch1(–1, 1);

do_branch1(1,–1);

do_branch1(1,1);

do_branch1(–1,0);

do_branch1(0,–1);

do_branch1(1,0);

do_branch1(0,1);

do_branch1(0,0);

По существу, это наивный подход “перебора всех альтернатив”, которой мы применили, заметив, что функция do_branch1 сравнивает значения с нулем с помощью операторов < и >. Для того чтобы выявить неправильные действия при положительных значениях переменной x, мы должны объединить вызовы функции с желаемыми результатами.

Обработка инструкций switch аналогична обработке инструкций if.

void do_branch1(int x, int y)  // плохая функция

 // неправильное использование инструкции switch

{

  if (y<0 && y<=3)

  switch (x) {

  case 1:

    cout << "Один\n";

    break;

  case 2:

    cout << "Два\n";

    case 3:

  cout << "Три\n";

  }

}

Здесь сделаны четыре классические ошибки.

• Мы проверяем значения неправильной переменной (y, а не x).

• Мы забыли об инструкции break, что приводит к неправильному действию при x==2.

• Мы забыли о разделе default (считая, что он предусмотрен инструкцией if).

• Мы написали y<0, хотя имели в виду 0.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже