Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.78/2070: Рейтинг темы: голосов - 2070, средняя оценка - 4.78
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
1

Распространенные ошибки

21.09.2014, 17:33. Показов 377879. Ответов 73
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Скачать pdf:
Часто встречающиеся Ошибки.pdf
Оглавление

Ошибки этапа компиляции
Программа не компилируется или компилируется с предупреждениями.
  1. Попытка модифицировать константу через указатель
  2. Неправильное понятие приведения
  3. Лишняя точка с запятой
  4. Отсутствие точки с запятой после определения классового типа
  5. Отсутствие возврата значения из функции
  6. Использование комментариев в #define
  7. Компилятор не находит iostream.h
  8. Внутри switch ошибка Case bypasses initialization of a local variable
  9. Передача двумерных массивов и указателей в функцию
  10. Не удается открыть файл stdafx.h
  11. Ошибка "unresolved external symbol _WinMain@16"
  12. Ошибка "This function or variable may be unsafe"
  13. Компилятор не находит шаблонов описанных в других файлах проекта
Ошибки этапа выполнения
Программа прекращает работу с сообщением об ошибке
  1. Выделение памяти без дальнейшего освобождения или неверное освобождение
  2. Возврат ссылки/указателя на локальную переменную
  3. Использование неинициализированной переменной
  4. Выход за пределы массива
  5. Ошибки при использовании функции scanf()
  6. Работа с локальной копией объекта, вместо работы с самим объектом
  7. Интерпретация одиночного char символа как символьной строки
  8. Ошибка преобразования: type ** в const type **
Неправильное поведение программы на этапе исполнения
Программа исполняется, но не так, как хотелось.
  1. Неожиданное закрытие окна
  2. "Неожиданное" целочисленное деление в арифметических выражениях
  3. Ошибки в логических выражениях
  4. Лишняя точка с запятой
  5. switch без break
  6. Сравнение вещественных чисел при вычислениях
  7. Сравнение char массивов
  8. Использование чисел, записанных в других системах счисления
  9. Проверки на принадлежность значения определенному интервалу
  10. Неверный аргумент тригонометрических функций
  11. Сравнение знаковой переменной с беззнаковой
  12. Использование запятой для отделения дробной части
  13. Забытое выделение тела цикла for, while и операторов if else
  14. Определение размера массива, переданного в качестве аргумента функции
  15. Порядок вычисления аргументов при вызове функции
  16. Некорректное использование логических переменных
  17. Локальная переменная экранирует переменную с таким же именем из вышестоящей области видимости
  18. Неправильное использование memset
  19. Ошибка при использовании счётчика цикла вне цикла
Алгоритмические ошибки
Ошибки, допущенные при разработке алгоритма
  1. Двойная перестановка строк или элементов массива
  2. Использование символа цифры вместо числа
Ошибки ввода-вывода
  1. Оставление символа '\n' в потоке ввода
  2. Ошибки при использовании функции scanf()
  3. При работе с fgetc чтение файла обрывается при достижении буквы 'я'
  4. При считывании из файла последний элемент читается дважды
  5. Запись сложных объектов в бинарный файл
Ошибки, связанные с отклонением от стандарта языка
  1. Неверный тип функции main()

Ошибки проектирования АТД (классов).
  1. Вызов виртуальной функции из конструктора
  2. Отсутствие точки с запятой после определения класса/структуры
  3. Неверный вызов конструктора базового класса из конструктора производного
  4. Неверный порядок при инициализации
  5. Нарушение правила ТРЕХ.
  6. Отсутствие виртуального деструктора в базовом классе
  7. Неправильное обращение к конструктору по умолчанию
  8. Не очевидные моменты с вызовом конструктора базового класса
  9. Неявно объявленный конструктор по умолчанию
  10. Перегрузка оператора >>
  11. Невозможно обратиться к protected члену, объявленному в базовом классе
Ошибки при использовании STL контейнеров
  1. Невалидные ссылки/указатели, при перемещении объектов
  2. Ошибки связанные с итераторами (кэширование размера контейнера)
  3. Ошибки связанные с итераторами (удаление элементов по итератору в циклах)
  4. Ошибки связанные с итераторами (префикс-постфиксные инкременты при удалении элементов в цикле)
36
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.09.2014, 17:33
Ответы с готовыми решениями:

Вывести самые распространенные женские и мужские имена
Помогите решить задачу пожалуйста! Написать программу, которая формирует файл записей данной...

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

Ошибки после компиляции на Visual Express 2012.Ошибки в теме
Добрый вечер ребят помогите пожалуйста.Программа написана на Visual Express 2012.Обясните что...

Распространенные ошибки
Оглавление Ошибки этапа компиляции (В процессе компиляции выдается либо сообщение об ошибке,...

73
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
21.09.2014, 17:42  [ТС] 2
Неожиданное закрытие окна

Когда консольное приложение запускается непосредственно из среды программирования,
то после выполнения последнего оператора программы ( return 0; ) окно закрывается.
Вставляйте оператор, ожидающий ввода символа с клавиатуры перед return:
C++
1
2
3
4
5
6
7
8
#include <iostream>
 
int main()
{
    ...
    system( "pause" );
    return 0;
}
или
C++
1
2
3
4
5
6
7
8
9
#include <iostream>
 
int main()
{
    ...
    cout << "Нажмите Enter для завершения";
    std::cin.get();
    return 0;
}
В этом случае надо учесть, что при вводе по командам типа cin>>xx; в потоке ввода остается символ конца строки, и cin.get() его прочтет. Хорошим тоном будет не забывать их удалять в момент ввода, например, так:
C++
1
(cin>>xx).get();
или с использованием библиотеки низкоуровневого ввода conio.h
(на *NIX системах она не используется):
C++
1
2
3
4
5
6
7
8
#include <conio.h>
 
int main()
{
    ...
    _getch();
    return 0;
}
14
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
21.09.2014, 17:56  [ТС] 3
Двойная перестановка строк или элементов массива

Рассмотрим на примере инвертирования строки
C++
1
2
3
4
5
6
7
8
char str[] = "123456";
int L = strlen( str );
for ( int i = 0; i < L; i++ )
{
    char tmp = str[i];
    str[i] = str[L - i - 1];
    str[L - i - 1] = tmp;
}
Когда мы дойдем до L/2, то строка уже перевернута.
Последующие итерации до L-1 вернут буквы на прежние места.

Исправленный вариант
C++
1
2
3
4
5
6
7
8
char str[] = "123456";
int L = strlen( str );
for ( int i = 0; i < L / 2; i++ )
{
    char tmp = str[i];
    str[i] = str[L - i - 1];
    str[L - i - 1] = tmp;
}
Аналогичные ошибки бывают и при перестановке строк матрицы,
при транспонировании матрицы и т.п.


*** Updated:
Дополнительные варианты переворота:

C++
1
2
3
4
5
6
7
#include <algorithm>
 
...
 
    for ( int i = 0; i < L / 2; i++ ) {
        std::swap( str[i], str[L - i - 1] );
    }
***

C++
1
2
3
4
5
#include <algorithm>
 
...
 
    std::reverse( str, str + L );
11
Модератор
Эксперт функциональных языков программированияЭксперт Python
36606 / 20334 / 4221
Регистрация: 12.02.2012
Сообщений: 33,654
Записей в блоге: 13
21.09.2014, 18:12 4
Попытка модифицировать константу через указатель

C++
1
2
3
4
5
6
7
8
9
10
11
void f( char * S )
{
    ...
    *(S + i) = 'Q'; // Будет ошибка !
}
 
int main()
{
    char * W = "Проба";
    f( W );
}
Исправить можно, заменив указатель массивом:
C++
1
2
3
4
5
6
7
8
9
10
11
void f( char * S )
{
    ...
    *(S + i) = 'Q'; 
}
 
int main()
{
    char W[] = "Проба"; // Под W выделится память на длину строки+1
    f( W );
}
Эта же ошибка и в таком примере:
C++
1
2
3
    // Неправильно
    char * S = "Hello";
    cin.getline( S, 255 );
C++
1
2
3
    // Правильно делать константный указатель на изменяемую строку, указав размер сразу
    char S[255] = "Hello"; // Указатель S менять нельзя, строку "Hello" можно
    cin.getline( S, 255 ); // Не больше чем выделено на массив, на начало которого указывает S
C++
1
2
3
4
5
    // Правильно выделять память с последующим освобождением. 
    char * S = new char [255]; // Требуется дальнейшее внимание, т.к. идет работа с памятью
    cin.getline( S, 255 );
    ...
    delete [] S;
13
Модератор
Эксперт по электронике
8909 / 6678 / 918
Регистрация: 14.02.2011
Сообщений: 23,524
21.09.2014, 18:33 5
Неправильное понятие приведения

Для приведения типов данных в C++ часто используются операции static_cast и reinterpret_cast.

Операцию приведения static_cast<новый_тип>( выражение ) можно использовать только в тех случаях,
когда компилятор выдает предупреждающее сообщение, например:
C++
1
2
double d = 1.5;
int n = static_cast<int>( d );
Обратите внимание, что круглые скобки вокруг выражения ( d ) ставятся всегда!

Если же выдается сообщение об ошибке, то нужно использовать операцию reinterpret_cast<новый_тип>( выражение ).

В этом случае только сам программист может вникнуть в суть преобразования и взять ответственность за преобразование на себя.
Вот пример, требующий приведение такого типа:
C++
1
2
3
4
5
6
7
8
9
struct typ1 { int t; };
struct typ2 { int g; };
 
    ...
 
    typ1 tp1 = { 1 };
    typ2 * p = reinterpret_cast<typ2 *>( &tp1 );
    p->g = 2;
    cout << typ1.t;
Здесь имеются два разных структурных типа typ1 и typ2.
К тому же и имена полей у них разные.
Но внутренне устройство одинаковое.
Т.е. мы понимаем, что типы данных абсолютно совместимы.
Осталось доказать это компилятору, что мы и делаем с помощью явного преобразования
C++
1
typ2 * p = reinterpret_cast<typ2 *>( &tp1 );
11
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
22.09.2014, 08:44  [ТС] 6
Ошибки в логических выражениях

Использование присваивания (=) вместо сравнения (==).
C++
1
if ( a = 2 )
всегда истина, т.к. переменной a присваивается двойка, что при приведению к bool дает true (подробное объяснение)
Рекомендации:
Читайте предупреждения компилятора, о таком присваивании он может сообщить (но не обязательно).

Можно в операции сравнения поменять местами левую и правую часть, тогда возникнет
ошибка компиляции (невозможно присвоить значение константе):
C++
1
 if ( 2 = a )
Использование побитовых операций & и | вместо логических&& и ||
C++
1
2
3
char n = 2, k = 1;
if ( k & n )    // результат false
if ( k && n )   // результат true
Здесь n в двоичном представлении равно 00000010, а k равно 00000001.
При их побитовом (поразрядном) умножении получим везде нули 00000000, что при приведении к bool даст false.
Во втором случае каждая переменная сначала приводится к bool,
в обоих случаях получается true, а потом выполняется логическое умножение.

С Вашего позволения оставлю это (Условия Йоды, или нотация Йоды) здесь.
5
Почетный модератор
Эксперт HTML/CSSЭксперт PHP
16844 / 6723 / 880
Регистрация: 12.06.2012
Сообщений: 19,967
22.09.2014, 10:48 7
Использование символа цифры вместо числа

Например, такой код
C++
1
2
3
4
5
char с;
int n;
c = '9';
n = c + 10;
printf( "%d", n );
n присвоится не ожидаемое число 19, а 67 (или, может, другое число, если в какой-то кодировке другой код).
Это все из-за того, что в таблице кодировки ASCII символу '9' соответствует код 57 и подставляется код этого символа. Чтобы избежать этого, т.е., именно получить число 9, а не код символа, необходимо вычесть код символа '0', который равен 48.
Можно вычесть и код как есть, но понятнее будет вычесть символ '0'.
C++
1
2
3
c = '9';
n = c - '0' + 10;
printf( "%d", n );
И теперь мы уже получим желаемое 19 .
6
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
22.09.2014, 11:19 8
Выделение памяти без дальнейшего освобождения или неверное освобождение

а) При выделении памяти через оператор new - освобождайте её с помощью оператора delete в конце программы
C++
1
2
3
int * a = new int;
// ... использование переменной
delete a; // перед выходом из программы
При отсутствии явного освобождения программа может вызывать утечку памяти.

б) Используйте для освобождения памяти, выделенной под массив, оператор delete [], а под обычные переменные - delete.
C++
1
2
3
4
5
6
7
int * a = new int;      // переменная
int * b = new int [2];  // массив
// ...
// delete [] a; // не ОК
delete a;       // ОК
// delete b;    // не ОК
delete [] b;    // ОК
Несмотря на то, что программа скомпилируется, попытка освобождения с помощью неверного оператора вызывает UB (неопределённое поведение), что приводит к трудноуловимым ошибкам.

в) Не стоит сочетать в программе, а тем более по отношению к одной и той же переменной/массиву, разные способы выделения/освобождения памяти. При выделении памяти с помощью malloc/calloc - освобождайте её с помощью функции free, при выделении через оператор new/new [] - освобождайте с помощью оператора delete/delete []. Стоит отметить, что использование сишных способов работы с памятью в целом не одобряется.
7
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
22.09.2014, 20:29 9
Возврат ссылки/указателя на локальную переменную
C++
1
2
3
4
5
6
7
8
9
10
11
int & foo()
{
    int x = 42;
    return x;
}
 
int * foo2() 
{ 
    int x = 42; 
    return &x; 
}
Локальные переменные, созданные на стеке, уничтожаются при выходе из области видимости (в данном случае это выход из функции), таким образом, память получает статус свободный и туда могут записаться какие-либо данные, либо, если это еще не успело произойти, там будет по прежнему находиться 42.
9
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
22.09.2014, 22:41 10
Использование неинициализированной переменной

Пожалуй, одна из самых распространённых ошибок.

Компилятор о такой ошибке может выдать предупреждающее сообщение такого типа
d:\current\cpp\test\test.c(9) : warning C4700: использована неинициализированная локальная переменная "fp"
Однако, этого не произойдет, если предупреждения об ошибках отключены. В Visual Studio эта настройка регулируется командой:
Проект -> Свойства -> Свойства конфигурации -> С/С++ -> Общие -> Уровень предупреждений

Вариаций на эту тему много, приведу пару примеров:
C++
1
2
int x; // предполагалось, например, int x;cin>>x;
std::cout << x; // выведет мусор - значение, которое находилось в переменной x
Чаще всего почему-то встречается вариант с использованием неинициализированного счётчика или переменной для подсчёта суммы, как показано ниже:
C++
1
2
3
4
5
6
7
8
int main()
{
    const int arrSize = 3, arr[arrSize] = { 1, 2, 3 };
    int sum; // ложное предположение, что переменная неявно инициализируется нулём, т.е. надо писать int sum=0;
    for ( int i = 0; i < arrSize; i++ )
        sum += arr[i]; // мы к "мусору" добавляем значение элемента массива
    std::cout << sum; // выведет не то, что вы ожидали
}
Кликните здесь для просмотра всего текста
Да, статические и глобальные переменные таки инициализируются нулём по-умолчанию, но если вы это знаете, то наверняка и с проблемой выше не сталкивались

Также эта проблема кроется в частичной инициализации объектов.
C++
1
2
3
4
5
6
7
8
9
10
11
12
struct A
{
    int x, y, z;
};
 
A a;
a.x = 2;
a.y = 3;
// а здесь мы с помощью Ctrl + C, Ctrl + V породили себе проблему
a.y = 4; // а хотели написать a.z=0;
// некоторые вычисления
std::cout << a.x << " " << a.y << " " << a.z;
Некоторые программисты советуют всегда инициализировать переменные при объявлении какими-нибудь дефолтными значениями. Это особенно важно при использовании указателей, отладка которых занимает много драгоценных часов. Также могу посоветовать объявлять переменные как можно ближе к месту их использования, это поможет отследить проблему.
4
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
22.09.2014, 23:25 11
Лишняя точка с запятой
C++
1
2
3
int i;
for ( i = 0; i < 10; ++i ); // лишняя ;
    cout << i << endl;
Выведет число 10. А не последовательность от 0 до 9. В данном случае просто 10 раз выполнится пустой цикл.

Такая же ошибка очень часто встречается в определении функций:
C++
1
2
3
4
5
// неверно:
int cube_func( int x ); // скопировали объявление функции, а ; убрать забыли
{
    return x * x * x;
}
вместо:
C++
1
2
3
4
5
// верно:
int cube_func( int x )
{
    return x * x * x;
}
7
Модератор
Эксперт CЭксперт С++
5284 / 2371 / 342
Регистрация: 20.02.2013
Сообщений: 5,770
Записей в блоге: 20
23.09.2014, 08:04 12
Неверный тип возвращаемого значения функции main()

C++
1
2
3
4
5
// неправильно:
void main()
{
    // some code
}
Согласно стандарту функция main() должна возвращать целочисленное значение:
C++
1
2
3
4
5
6
// правильно:
int main()
{
    // some code
    return 0;
}
Замечание.
Для некоторых компиляторов (в том числе и Visual Studio) допускаются и другие возвращаемые типы.
И вариант:
C++
1
void main()
может использоваться.
Однако, следует помнить, что он может восприниматься как ошибка другими компиляторами.
8
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
23.09.2014, 09:18 13
Отсутствие точки с запятой после определения классового типа
C++
1
2
3
4
5
6
7
8
9
10
struct A
{
    int n;
} // забыли ;
 
int main()
{
    A a;
    return 0;
}
Данная ошибка приводит компилятор в ступор:
1>d:\current\cpp\test\tset.cpp(10) : error C2628: недопустимый 'A' с последующим 'int' (возможно, отсутствует ';')
1>d:\current\cpp\test\tset.cpp(11) : error C3874: возвращаемый тип 'main' должен быть 'int', а не 'A'
1>d:\current\cpp\test\tset.cpp(12) : error C2143: синтаксическая ошибка: отсутствие ";" перед "."
1>d:\current\cpp\test\tset.cpp(12) : error C2143: синтаксическая ошибка: отсутствие ";" перед "."
1>d:\current\cpp\test\tset.cpp(13) : error C2664: A::A(const A &): невозможно преобразовать параметр 1 из 'int' в 'const A &'
1> Причина: невозможно преобразовать 'int' в 'const A'
1> Ни один конструктор не смог принять исходный тип, либо разрешение перегрузки конструктора неоднозначно
4
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
23.09.2014, 17:29 14
Сравнение вещественных чисел при вычислениях

Поскольку арифметические вычисления для чисел с плавающей запятой выполняются с некоторой погрешностью, то их сравнение на равенство будет некорректным, например:
C++
1
 if ( a - b == 0 )
Соответственно и сравнивать их надо с некоторой точностью (которая зависит от поставленной задачи), например
C++
1
 if ( fabs( a - b ) < 1e-3 )
8
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
24.09.2014, 00:01 15
Сравнение символьных массивов
При сравнение char массивов через операторы <, ==, !=, >, <=, >= мы на самом деле сравниваем не содержимое, а указатели.
Для правильного сравнения стоит использовать специальную функцию strcmp.
C++
1
2
3
4
5
6
7
char c1[] = "b", c2[] = "a";
if ( c1 < c2 ) // ошибка! ожидаем сравнения в лексикографическом порядке
    printf( "I hope this line wouldn't printed on the screen\n" );
if ( strcmp( c1, c2 ) < 0 ) // правильное сравнение
    printf( "And it was true\n" );
else
    printf( "But I was wrong :(" );
9
Почетный модератор
Эксперт HTML/CSSЭксперт PHP
16844 / 6723 / 880
Регистрация: 12.06.2012
Сообщений: 19,967
24.09.2014, 11:52 16
Использование чисел, записанных в других системах счисления

Может показаться, что значения следующих двух переменных одинаковые:
C++
1
2
    int x = 123;
    int y = 0123;
Однако это совсем не так. Первое число (123) записано в десятичной системе счисления. Т.к. по умолчанию (и чаще всего) мы работаем с десятичной системой счисления, то x так и будет равен 123.
Второе же число (0123) записано в восьмеричной системе счисления и при переводе в десятичную будет равно 83, а не 123. Если вы работаете с десятичной системой счисления, то не добавляйте цифру "0" перед числом.


Проверка на принадлежность значения определенному интервалу

Иногда при проверке принадлежности значения переменной определенному интервалу можно увидеть нечто подобное
C++
1
    if ( 0 <= x <= 10 )
Несмотря на кажущуюся логичность, этот код не проверяет на то, что x лежит между 0 и 10.
Если разбить на шаги, то они будут следующими:
Т.к. оператор сравнения <= левоассоциативен (т.е., выполняется слева направо), то первым шагом будет сравнение 0 и x
1. 0 <= x. Результат сравнения - true или false, которые будут преобразованы в 1 или 0 соответственно.
2. сравниваем полученный результат с 10. 10 больше и 1, и 0. Следовательно, условие всегда истинно.
В общем случае, можно сказать, что при сравнении подобным образом, если последнее число (в примере это число 10) больше или равно 1, то условие всегда истинно.
Проверку на принадлежность интервалу правильно записывать с помощью логического оператора И.
C++
1
    if ( 0 <= x && x <= 10 )
Ошибкой также является использование запятой, вместо логического И
C++
1
    if ( 0 <= x , x <= 10 )
В этом случае, значения выражения 0 <= x никак не используется. Результатом будет значение выражения x <= 10.

Иногда вместо логического И используют логическое ИЛИ.
Выражение
C++
1
    if ( 0 <= x || x <= 10 )
не означает, что значение x лежит между 0 и 10. Это может быть вообще любое число. Почему так происходит:
1. Проверяем первое условие. Если x больше или равен нулю, то истина. Значит, любое положительное значение уже истина.
2. Если первое условие не выполнилось, то проверяем второе условие. Любое отрицательное число (а предыдущее условие могло не пройти только отрицательное значение) меньше 10, значит, условие тоже истинное.
Следовательно, условие всегда истинное.
4
Почетный модератор
Эксперт HTML/CSSЭксперт PHP
16844 / 6723 / 880
Регистрация: 12.06.2012
Сообщений: 19,967
24.09.2014, 12:11 17
Отсутствие возврата значения из функции

Например, следующая функция
C++
1
2
3
4
5
int f( int x )
{
    if ( x == 10 )
        return 1;
}
является ошибочной: в случае невыполнения условия возврата из функции нет никакого.
Для избежания этого из функции обязательно должен быть возврат, вне зависимости от выполнения или невыполнения условия.
C++
1
2
3
4
5
6
int f( int x )
{
    if ( x == 10 )
        return 1;
    return 0;
}
Компилятор может выдать предупреждающее сообщение:
1>d:\current\cpp\test\test.c(8) : warning C4715: f: значение возвращается не при всех путях выполнения
Для этого надо установить соответствующий уровень предупреждений компилятора.
В Visual Studio это делается через команду меню:
Проект -> Свойства -> Свойства конфигурации -> С/С++ -> Общие -> Уровень предупреждений -> Уровень 4 (/W4).

Реальный пример - функция поиска позиции первого вхождения символа в строку.
C++
1
2
3
4
5
6
7
int indexOf( const char * str, const char c )
{
    for ( int i = 0; str[i]; ++i )  // пробегаемся по строке
        if ( str[i] == c )          // если текущий символ - искомый
            return i;               // то возвращаем индекс этого символа
    return -1;                      // если цикл прошелся и возврата не выполнено (символ не найден), возвращаем -1
}
3
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
24.09.2014, 12:32  [ТС] 18
Оставление символа '\n' в потоке ввода:
C++
1
2
3
4
cout << "введите n:";
int n; cin >> n;    // вводится число после нажатия Enter
cout << "введите символ:";
char c; cin.get(c); // хотим ввести символ из новой строки, но вместо него вводится '\n'
C++
1
2
3
4
cout << "введите n:";
int n; cin >> n;    // вводится число после нажатия Enter
cout << "введите строку:";
char c[100]; cin.getline(c,100);    // хотим ввести новую строку, но вводится пустая строка
исправление ошибки
C++
1
2
3
4
5
6
cout << "введите n:";
int n;
(cin >> n).get();   // вводим число и пропускаем один символ
cout << "введите символ:";
char c;
cin.get(c);         // вводится символ на новой строке ( !!!  '\n' второй строки еще не прочитали).
Вместо cin.get() можно просто пропустить символы:
C++
1
2
cin.ignore( k, '\n' );                  // k -  пропускаемое к-во символов,  параметр '\n' можно опускать 
cin.ignore( cin.rdbuf()->in_avail() );  // пропустить все оставшиеся символы
Можно также в цикле прочитать оставшиеся символы
C++
1
while ( cin.get() != '\n' );
Третий способ - синхронизация ввода с помощью cin.sync():
C++
1
2
3
4
5
6
7
8
cout<<"введите n:";
int n;
cin >> n;
cin.sync(); // вводим число и сбрасываем остаток строки
cout << "введите символ:";
char c;
cin >> c;
cin.sync(); // вводим символ на новой строке и тоже сбрасываем остаток строки.
В общем, возможности большие. Главное помнить об этой проблеме!
25
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
24.09.2014, 12:35  [ТС] 19
Выход за пределы массива
C++
1
2
3
    int arr[5] = { 1, 2, 3, 4, 5 };
    for ( int i = 1;  i <= 5; ++i )
        printf( "%d\n", arr[i] ); // выведет 2 3 4 5 и ... всё что угодно
Индексы массивов в C++ начинаются с нуля. Для массива из N элементов допустимые индексы лежат в диапазоне [0..N-1]. Чтение или запись информации вне выделенной памяти приводит к неопределенному поведению программы.

Также часто встречается выход за пределы массива в строках в стиле C из-за отсутствии терминального нуля:
C++
1
2
3
4
char str[2] = { 'a', 'b' };
cout << str;                                // результат вывода непредсказуем, т.к. неизвестно сколько символов надо выводить
for ( int i = 0; i < strlen( str ); i++ )   // не известно, что вернет strlen()
     str[i] = 'x';                          // соответственно неизвестно к каким элементам массива обратимся.
Исправленный вариант
C++
1
2
3
4
char str[3] = { 'a', 'b', 0 };              // или char str[3] = "ab";
printf( "%s", str );                        // вывод ab
for ( int i = 0; i < strlen( str ); i++ )   // strlen() возвратит 2
    str[i] = 'x';                           // в массиве окажется строка "xx"
4
Модератор
Эксперт С++
13508 / 10758 / 6412
Регистрация: 18.12.2011
Сообщений: 28,724
24.09.2014, 12:38  [ТС] 20
Лучший ответ Сообщение было отмечено Volga_ как решение

Решение

switch без break
C++
1
2
3
4
5
6
switch( i )
{
    case 0: cout << "zero\n";
    case 1: cout << "one\n";
    default: cout << "other\n"; 
}
При i равном 0 будет выведено zero one other. При i равном 1 будет выведено one other. Т.е. без break происходит "проваливание" к следующей метке. В большинстве случаев, приведенный выше код является ошибочным, но иногда такое поведение может быть задуманным. И в этих случаях следует для очевидности указать в комментарии, что отсутствие break это не ошибка, а явная задумка автора.
2
24.09.2014, 12:38
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.09.2014, 12:38
Помогаю со студенческими работами здесь

безопасность и распространенные ошибки
Тут наткнулся на очень интересные тексты: http://werad.narod.ru/articles/programm6.html ...

безопасность и распространенные ошибки
Тут наткнулся на очень интересные тексты: http://werad.narod.ru/articles/programm6.html ...

Распространенные ошибки SEO и ASP.NET 2.0
Здравствуйте, существуют несколько СЕО проблем при использовании ASP.NET, ниже я опишу эти...

Самые распространенные строки
type Mytype = record name:string; surname:string; end; var Students:Mytype; ...

Самые распространённые фамилии
Здравствуйте! Для реализации автоподстановки фамилии нужно как-то выявить, например, 1 (10, 15,...

Распространённые схемы мошейничества с вайбером
Использовался старый кнопочный телефон. Схема: - в одном из телеграмм чатов предложили...

Самые распространенные мужское и женское имена
Здрасти всем. Помогите справиться с решением задачи. Во входном файле записана следующая...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru