Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1, средняя оценка - 5.00
zss
Модератор
Эксперт С++
6531 / 6093 / 2007
Регистрация: 18.12.2011
Сообщений: 15,850
Завершенные тесты: 1
#1

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

21.09.2014, 17:33. Просмотров 63789. Ответов 60
Метки нет (Все метки)

Оглавление

Ошибки этапа компиляции
Программа не компилируется или компилируется с предупреждениями.
  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"
Ошибки этапа выполнения
Программа прекращает работу с сообщением об ошибке
  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. Локальная переменная экранирует переменную с таким же именем из вышестоящей области видимости
  19. Неправильное использование memset
Алгоритмические ошибки
Ошибки, допущенные при разработке алгоритма
  1. Двойная перестановка строк или элементов массива
  2. Использование символа цифры вместо числа
Ошибки ввода-вывода
  1. Оставление символа '\n' в потоке ввода
  2. Ошибки при использовании функции scanf()
  3. При работе с fgetc чтение файла обрывается при достижении буквы 'я'
  4. При считывании из файла последний элемент читается дважды
Ошибки, связанные с отклонением от стандарта языка
  1. Неверный тип функции main()

Ошибки проектирования АТД (классов).
  1. Вызов виртуальной функции из конструктора
  2. Отсутствие точки с запятой после определения класса/структуры
  3. Неверный вызов конструктора базового класса из конструктора производного
  4. Неверный порядок при инициализации
  5. Нарушение правила ТРЕХ.
  6. Отсутствие виртуального деструктора в базовом классе
  7. Неправильное обращение к конструктору по умолчанию
  8. Не очевидные моменты с вызовом конструктора базового класса
  9. Неявно объявленный конструктор по умолчанию
  10. Перегрузка оператора >>
Ошибки при использовании STL контейнеров
  1. Невалидные ссылки/указатели, при перемещении объектов
  2. Ошибки связанные с итераторами (кэширование размера контейнера)
  3. Ошибки связанные с итераторами (удаление элементов по итератору в циклах)
  4. Ошибки связанные с итераторами (префикс-постфиксные инкременты при удалении элементов в цикле)
25
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.09.2014, 17:33
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Распространенные ошибки (C++):

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

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

Найти ошибки в коде и исправить эти ошибки (Наследование) - C++
Вот в общем 3 файла, изучаю наследование на примере односвязного и двусвязного списков: list.h (inline) #pragma once class list...

Найти ошибки в коде и исправить эти ошибки - C++ - C++
Судя по вываливающейся ошибки, идет двойное освобождение памяти. У самого не получается отловить откуда. A.h #pragma once ...

Найти ошибки в коде и исправить эти ошибки - C++
Есть у меня вот такой код: #include <iostream> using namespace std; class A{ private: int* a; size_t size_; ...

Распространенные ошибки - C (СИ)
Оглавление Ошибки этапа компиляции (В процессе компиляции выдается либо сообщение об ошибке, либо предупреждение) - Попытка...

60
zss
Модератор
Эксперт С++
6531 / 6093 / 2007
Регистрация: 18.12.2011
Сообщений: 15,850
Завершенные тесты: 1
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;
}
или с использованием библиотеки низкоуровневого ввода conio.h
(на *NIX системах она не используется):
C++
1
2
3
4
5
6
7
8
#include <conio.h>
 
int main()
{
    ...
    _getch();
    return 0;
}
10
zss
Модератор
Эксперт С++
6531 / 6093 / 2007
Регистрация: 18.12.2011
Сообщений: 15,850
Завершенные тесты: 1
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;
}
Аналогичные ошибки бывают и при перестановке строк матрицы,
при транспонировании матрицы и т.п.
9
Catstail
Модератор
22835 / 11201 / 1812
Регистрация: 12.02.2012
Сообщений: 18,439
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;
9
ValeryS
Модератор
6709 / 5118 / 482
Регистрация: 14.02.2011
Сообщений: 17,199
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 );
10
zss
Модератор
Эксперт С++
6531 / 6093 / 2007
Регистрация: 18.12.2011
Сообщений: 15,850
Завершенные тесты: 1
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, а потом выполняется логическое умножение.

С Вашего позволения оставлю это (Условия Йоды, или нотация Йоды) здесь.
4
KOPOJI
Эксперт HTML/CSSЭксперт PHP
16701 / 6623 / 433
Регистрация: 12.06.2012
Сообщений: 19,880
Завершенные тесты: 1
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 .
5
MrGluck
Модератор
Эксперт CЭксперт С++
7491 / 4606 / 692
Регистрация: 29.11.2010
Сообщений: 12,592
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 []. Стоит отметить, что использование сишных способов работы с памятью в целом не одобряется.
4
MrGluck
Модератор
Эксперт CЭксперт С++
7491 / 4606 / 692
Регистрация: 29.11.2010
Сообщений: 12,592
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.
7
MrGluck
Модератор
Эксперт CЭксперт С++
7491 / 4606 / 692
Регистрация: 29.11.2010
Сообщений: 12,592
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;
Некоторые программисты советуют всегда инициализировать переменные при объявлении какими-нибудь дефолтными значениями. Это особенно важно при использовании указателей, отладка которых занимает много драгоценных часов. Также могу посоветовать объявлять переменные как можно ближе к месту их использования, это поможет отследить проблему.
3
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
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;
}
5
gru74ik
Модератор
Эксперт CЭксперт С++
4196 / 1844 / 198
Регистрация: 20.02.2013
Сообщений: 4,991
Записей в блоге: 22
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()
может использоваться.
Однако, следует помнить, что он может восприниматься как ошибка другими компиляторами.
6
MrGluck
Модератор
Эксперт CЭксперт С++
7491 / 4606 / 692
Регистрация: 29.11.2010
Сообщений: 12,592
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> Ни один конструктор не смог принять исходный тип, либо разрешение перегрузки конструктора неоднозначно
3
daslex
1285 / 529 / 109
Регистрация: 02.08.2011
Сообщений: 2,750
23.09.2014, 17:29 #14
Сравнение вещественных чисел при вычислениях

Поскольку арифметические вычисления для чисел с плавающей запятой выполняются с некоторой погрешностью, то их сравнение на равенство будет некорректным, например:
C++
1
 if ( a - b == 0 )
Соответственно и сравнивать их надо с некоторой точностью (которая зависит от поставленной задачи), например
C++
1
 if ( fabs( a - b ) < 1e-3 )
6
MrGluck
Модератор
Эксперт CЭксперт С++
7491 / 4606 / 692
Регистрация: 29.11.2010
Сообщений: 12,592
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 :(" );
5
24.09.2014, 00:01
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.09.2014, 00:01
Привет! Вот еще темы с ответами:

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

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

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

Вирус блокирует выход на сайт вк и другие распространенные сайты - Удаление вирусов
я чайник поэтому если что то не загрузилось..напишите пожалуйста, и помогите... второй день вожусь с этим. Hosts чистый, drweb выявил один...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru