Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Функция возвращает локальные переменныеСодержание книги
Поиск на нашем сайте (баг редкий, катастрофический) Переменные, объявленные в теле функции, хранят некоторые локальные данные. Если данные выделены динамически, они находятся в куче. Если же переменные объявлены статически, они будут сохранены в стеке. Если функция запрограммирована так, что она возвращает адрес локальной переменной, то программа, которая обратится по этому адресу, получит доступ к стеку. int foo () { int ch; do { ch = getch (); } while (ch < ‘0’ || ch > ‘9’); //вводим цифру return &ch; } Функция возвращает адрес локальной переменной, которая находится в стеке. Но самой переменной уже нет, после возврата из функции часть стека, занятая ее данными, была освобождена и будет отдана другим функциям. В результате после попытки использовать для чтения или для записи адрес, который вернула функция, возникает ошибка. Освобождение уже освобожденных ресурсов. (баг частый, крупный) Программист пытается освободить память, которая уже освобождена. В общем случае ресурсы сначала выделяются, а затем освобождаются. При повторном освобождении может возникнуть зацикливание. void swap (int *x, int *y) { //крайне неэффективная реализация функции обмена двух int int *tmp; tmp = (int *) malloc (sizeof (int)); if (*x == *y) free (tmp); *tmp = *x; *x = *y; *y = *tmp; free (tmp); } int main () { int a, b; a = 3; b = 4; swap (&a, &b); // ошибки нет a = 5; b = 5; swap (&a, &b); // ошибка } Разыменование NULL (баг частый, катастрофический) К этому багу ведет некорректная инициализация или ее отсутствие. Чтобы разыменовать область памяти, нужно ее до этого выделить. float *arr; int n; printf (“ n = “); scanf (“%i”, &n); if (n > 0) arr = (float *) malloc (n * sizeof (float)); *arr = 1.0; // если n <= 0, то возникнет ошибка Также данная ошибка может возникнуть из-за использования псевдонимов (две переменные ссылаются на один и тот же объект; после того, как память освобождена через одну переменную, делается попытка использовать другую переменную). int *ptr1; int *ptr2; ptr1 = (int *) malloc (sizeof (int)); ptr2 = ptr1; ... free (ptr1); *ptr2 = 666; Псевдонимы (алиасы, aliases) Использование программистом большого количества псевдонимов для одной и той же переменой может привести к появлению ошибок. Передача функции фактических параметров по ссылке (баг частый, крупный) Некоторой функции передаются две ссылки одного и того же типа. Функция изменяет данные, которые находятся по первой ссылке, используя данные, полученные по второй ссылке. Если обе ссылки совпадают, возникает ошибка Пример 1. char *src; // какой-то код char *destn = src; strcat (src, destn); /* если фактические параметры src и destn псевдонимы, то возникает баг*/
Пример 2. #include < stdio.h > #include < conio.h > void sum (int &a, int &b, int &c) { // очень медленная, но работающая функция сложения двух чисел с = 0; for (int i = 0; i < a; ++i) c++; for (int i = 0; i < b; ++i) c++; } int main () { int aa, bb, cc; aa = 3; bb = 4; // правильный вариант printf (“ aa = %i \n bb = %i \n”, aa, bb); sum (aa, bb, cc); printf (“ aa + bb = %i\n”, cc); // неправильный вариант printf (“ aa = %i \n bb = %i \n”, aa, bb); sum (aa, bb, aa); printf (“ aa + bb = %i\n”, aa); getch (); return 0; } Во втором случае использования функции sum (aa, bb, aa) переменная aa обнулится сразу в начале функции sum. Затем произойдет инициализация первого цикла int i = 0, проверка условия цикла i < a вернет false, и первый цикл не выполнится ни разу. Во втором цикле значение переменной aa увеличится bb раз на 1 и станет равным bb. В итоге на экран будет выдано aa = 3 bb = 4 aa + bb = 7 aa = 3 bb = 4 aa + bb = 4 Ошибки данных. Арифметические ошибки Неинициализированная память (баг редкий, крупный) Пример 1. Поиск максимума в массиве. int imax, max, arr [ 10 ]; ... max = arr[0]; for (int i = 1; i < 10; ++i) if (arr [ i ] > max) { max = arr [ i ]; imax = i; } printf (“ max = a [ %i ] = %i\n”, imax, max); Если максимальным является элемент arr [ 0 ], то переменная imax останется неинициализированной, и на экране вполне может появиться что-нибудь вроде max = arr [ -13267 ] = 11 Пример 2. Для инициализации переменной может быть использован оператор switch. Но некоторые случаи могут быть пропущены из-за того, что соответствующие пути выполнения не были предусмотрены. int x; switch (getch ()) { case ‘0’: x = 0; break; case ‘1’: x = 1; break; } return x; Простейшее решение проблемы – использовать объявление с инициализацией: int x = -1; и проверять возвращенное функцией значение { 0, 1, -1 }. Более сложная, но лучшая стратегия – рассмотреть все возможные сценарии и пути выполнения в операторе switch.
|
||
|
Последнее изменение этой страницы: 2021-03-09; просмотров: 147; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.128 (0.006 с.) |