Неопределенный порядок побочных эффектов 


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



ЗНАЕТЕ ЛИ ВЫ?

Неопределенный порядок побочных эффектов



В выражении не всегда удается определить точно порядок выполнения побочных эффектов.

В следующем коде в зависимости от используемого компилятора i/i++ будет равно либо 0, либо 1.

int foo (int n) {

printf (“foo got %d\n”, n);

return 0;

}

int bar (int n){

printf (“ bar got %d\n”, n);

return 0;

}

int main () {

int m = 0;

int fun_array [ 3] (int);

int  i = 1;

int ii = i/++i;

 printf (“ \ni/++i = %d, “, ii);

fun_array [ 1 ] = foo;

fun_array [ 2 ] = bar;

fun_array [++m ](++m);

return 0;

}

На экран выводится то «i/++i = 1», то «i/++i = 0»; то «foo got 2», то «bar got 2».

Избегайте таких конструкций!

Ошибки обработки строк

Во многих случаях функции обработки строк strcpy, sprint, gets и другие используются неверно.

Например, одним из фактических параметров может оказаться NULL.

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

В функции копирования strcpy () строка source  может быть большего размера, чем строка dest. В результате может произойти переполнение буфера.

Прочие часто встречающиеся ошибки. Ошибки начинающих программистов

Отсутствие break в операторе switch. «Проваливание» switch

Пример.

int   x = 2;

switch (x) {

case 2: printf (“Two\n”);

case 3: printf(“Three\n”);

}

Вывод программы:

Two

Three

Следует проставить операторы break после каждой ветви case оператора switch:

int  x = 2;

switch (x) {

case 2: printf (“Two\n”); break;

 

case 2: printf (“Three\n”);

break; /* не обязательно, но рекомендуется, т. к. позже могут быть добавлены        

                дополнительные ветви*/

}

4.2. Использование = вместо ==

Операция  = используется только для присваивания и возвращает присвоенное значение.

Операция == используется только для сравнения и возвращает целочисленное значение (0 – ложь, не 0 – истина). Компилятор не указывает ошибку в следующем примере (но укажет предостережение – warning):

int x = 5;

if (x = 6)

printf (“ x equals 6\n”);

На экран выводится «x equals 6»

Рекомендуется помещать любые константы слева от операции сравнения ==. Тогда ошибочное использование = вместо == станет ошибкой времени компиляции:

6 = x; //компилятор укажет на ошибку

Ошибки при использовании функции scanf ()

Существует две наиболее распространенные ошибки использования scanf ():

· Ошибка употребления амперсанда & перед аргументом

scanf должна получить адрес переменной, чтоб сохранить введенные данные:

  int x;

  char *st = malloc (31);

  scanf (“%d”, &x);//амперсанд требуется, чтоб передать адрес функции scanf

scanf (“ %30s”, st);//Здесь не нужен амперсанд, имя st само является указателем

При ошибочной записи scanf (“%d”, x) произойдет запись введенного значения не в переменную x, а по адресу, численно равному текущему значению переменной x.

· Использование неверного спецификатора формата (относится также и к printf ())

Компилятор С не проверяет соответствие спецификаторов формата и фактических параметров функции scanf(). Чаще всего встречается ошибочное использование формата %f для ввода значений типа double ( для double нужно использовать %lf):

double x;

scanf (“%f”, &x); // ошибка!

Также встречается неверное использование спецификаторов формата %c и %s для вывода строк и символов соответственно. Для вывода символов необходимо использовать %c, а для вывода строк - %s.

char x = ‘0’;

char  *y = “qwerty”;

printf (“%c”, y); //ошибка!

printf (“%s\n”, x); // опять ошибка!

Размер массива

Индекс массива в С  всегда начинается с 0. К последнему элементу массива a из n элементовможно обратиться через a [ n – 1].

int  a[10];// индексы элементов массива 0.. 9

for (int  i = 0; i < 10; ++i)

a[ i] = i * i;

Целочисленное деление

В отличие от Pascal, С использует операцию / и для вещественного, и для целочисленного деления. Если оба операнда целочисленные, то используется целочисленное деление, в противном случае – вещественное.

double halfe = 1 / 2; // halfe = 0!

double halfe = 1.0 / 2; // теперь halfe = 0.5

Если оба операнда целые, но требуется вещественное деление, один из операндов нужно привести к вещественному типу:

int x = 5, y = 2;

double d = x / y; // d=2

double d1 = (double) x/ y; // d1=2.5



Поделиться:


Последнее изменение этой страницы: 2021-03-09; просмотров: 63; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

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