Функция возвращает локальные переменные 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Функция возвращает локальные переменные



(баг редкий, катастрофический)

Переменные, объявленные в теле функции, хранят некоторые локальные данные. Если данные выделены динамически, они находятся в куче. Если же переменные объявлены статически, они будут сохранены в стеке.

Если функция запрограммирована так, что она возвращает адрес локальной переменной, то программа, которая обратится по этому адресу, получит доступ к стеку.

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; просмотров: 70; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.141.244.201 (0.01 с.)