C++ — Помогите исправить ошибку в программе


Содержание

Как искать и исправлять ошибки в коде

Искать ошибки в программах — непростая задача. Здесь нет никаких готовых методик или рецептов успеха. Можно даже сказать, что это — искусство. Тем не менее есть общие советы, которые помогут вам при поиске. В статье описаны основные шаги, которые стоит предпринять, если ваша программа работает некорректно.

Шаг 1: Занесите ошибку в трекер

После выполнения всех описанных ниже шагов может так случиться, что вы будете рвать на себе волосы от безысходности, все еще сидя на работе, когда поймете, что:

  1. Вы забыли какую-то важную деталь об ошибке, например, в чем она заключалась.
  2. Вы могли делегировать ее кому-то более опытному.

Трекер поможет вам не потерять нить размышлений и о текущей проблеме, и о той, которую вы временно отложили. А если вы работаете в команде, это поможет делегировать исправление коллеге и держать все обсуждение в одном месте.

Вы должны записать в трекер следующую информацию:

  1. Что делал пользователь.
  2. Что он ожидал увидеть.
  3. Что случилось на самом деле.

Это должно подсказать, как воспроизвести ошибку. Если вы не сможете воспроизвести ее в любое время, ваши шансы исправить ошибку стремятся к нулю.

Шаг 2: Поищите сообщение об ошибке в сети

Если у вас есть сообщение об ошибке, то вам повезло. Или оно будет достаточно информативным, чтобы вы поняли, где и в чем заключается ошибка, или у вас будет готовый запрос для поиска в сети. Не повезло? Тогда переходите к следующему шагу.

Шаг 3: Найдите строку, в которой проявляется ошибка

Если ошибка вызывает падение программы, попробуйте запустить её в IDE под отладчиком и посмотрите, на какой строчке кода она остановится. Совершенно необязательно, что ошибка будет именно в этой строке (см. следующий шаг), но, по крайней мере, это может дать вам информацию о природе бага.

Шаг 4: Найдите точную строку, в которой появилась ошибка

Как только вы найдете строку, в которой проявляется ошибка, вы можете пройти назад по коду, чтобы найти, где она содержится. Иногда это может быть одна и та же строка. Но чаще всего вы обнаружите, что строка, на которой упала программа, ни при чем, а причина ошибки — в неправильных данных, которые появились ранее.

Если вы отслеживаете выполнение программы в отладчике, то вы можете пройтись назад по стектрейсу, чтобы найти ошибку. Если вы находитесь внутри функции, вызванной внутри другой функции, вызванной внутри другой функции, то стектрейс покажет список функций до самой точки входа в программу (функции main() ). Если ошибка случилась где-то в подключаемой библиотеке, предположите, что ошибка все-таки в вашей программе — это случается гораздо чаще. Найдите по стектрейсу, откуда в вашем коде вызывается библиотечная функция, и продолжайте искать.

Шаг 5: Выясните природу ошибки

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

  1. Ошибка на единицу
    Вы начали цикл for с единицы вместо нуля или наоборот. Или, например, подумали, что метод .count() или .length() вернул индекс последнего элемента. Проверьте документацию к языку, чтобы убедиться, что нумерация массивов начинается с нуля или с единицы. Эта ошибка иногда проявляется в виде исключения Index out of range .
  2. Состояние гонки
    Ваш процесс или поток пытается использовать результат выполнения дочернего до того, как тот завершил свою работу. Ищите использование sleep() в коде. Возможно, на мощной машине дочерний поток выполняется за миллисекунду, а на менее производительной системе происходят задержки. Используйте правильные способы синхронизации многопоточного кода: мьютексы, семафоры, события и т. д.
  3. Неправильные настройки или константы
    Проверьте ваши конфигурационные файлы и константы. Я однажды потратил ужасные 16 часов, пытаясь понять, почему корзина на сайте с покупками виснет на стадии отправки заказа. Причина оказалась в неправильном значении в /etc/hosts , которое не позволяло приложению найти ip-адрес почтового сервера, что вызывало бесконечный цикл в попытке отправить счет заказчику.
  4. Неожиданный null
    Бьюсь об заклад, вы не раз получали ошибку с неинициализированной переменной. Убедитесь, что вы проверяете ссылки на null , особенно при обращении к свойствам по цепочке. Также проверьте случаи, когда возвращаемое из базы данных значение NULL представлено особым типом.
  5. Некорректные входные данные
    Вы проверяете вводимые данные? Вы точно не пытаетесь провести арифметические операции с введенными пользователем строками?
  6. Присваивание вместо сравнения
    Убедитесь, что вы не написали = вместо == , особенно в C-подобных языках.
  7. Ошибка округления
    Это случается, когда вы используете целое вместо Decimal , или float для денежных сумм, или слишком короткое целое (например, пытаетесь записать число большее, чем 2147483647, в 32-битное целое). Кроме того, может случиться так, что ошибка округления проявляется не сразу, а накапливается со временем (т. н. Эффект бабочки).
  8. Переполнение буфера и выход за пределы массива
    Проблема номер один в компьютерной безопасности. Вы выделяете память меньшего объема, чем записываемые туда данные. Или пытаетесь обратиться к элементу за пределами массива.
  9. Программисты не умеют считать
    Вы используете некорректную формулу. Проверьте, что вы не используете целочисленное деление вместо взятия остатка, или знаете, как перевести рациональную дробь в десятичную и т. д.
  10. Конкатенация строки и числа
    Вы ожидаете конкатенации двух строк, но одно из значений — число, и компилятор пытается произвести арифметические вычисления. Попробуйте явно приводить каждое значение к строке.
  11. 33 символа в varchar(32)
    Проверяйте данные, передаваемые в INSERT , на совпадение типов. Некоторые БД выбрасывают исключения (как и должны делать), некоторые просто обрезают строку (как MySQL). Недавно я столкнулся с такой ошибкой: программист забыл убрать кавычки из строки перед вставкой в базу данных, и длина строки превысила допустимую как раз на два символа. На поиск бага ушло много времени, потому что заметить две маленькие кавычки было сложно.
  12. Некорректное состояние
    Вы пытаетесь выполнить запрос при закрытом соединении или пытаетесь вставить запись в таблицу прежде, чем обновили таблицы, от которых она зависит.
  13. Особенности вашей системы, которых нет у пользователя
    Например: в тестовой БД между ID заказа и адресом отношение 1:1, и вы программировали, исходя из этого предположения. Но в работе выясняется, что заказы могут отправляться на один и тот же адрес, и, таким образом, у вас отношение 1:многим.

Если ваша ошибка не похожа на описанные выше, или вы не можете найти строку, в которой она появилась, переходите к следующему шагу.

Шаг 6: Метод исключения

Если вы не можете найти строку с ошибкой, попробуйте или отключать (комментировать) блоки кода до тех пор, пока ошибка не пропадет, или, используя фреймворк для юнит-тестов, изолируйте отдельные методы и вызывайте их с теми же параметрами, что и в реальном коде.

Попробуйте отключать компоненты системы один за другим, пока не найдете минимальную конфигурацию, которая будет работать. Затем подключайте их обратно по одному, пока ошибка не вернется. Таким образом вы вернетесь на шаг 3.

Шаг 7: Логгируйте все подряд и анализируйте журнал

Пройдитесь по каждому модулю или компоненту и добавьте больше сообщений. Начинайте постепенно, по одному модулю. Анализируйте лог до тех пор, пока не проявится неисправность. Если этого не случилось, добавьте еще сообщений.

Ваша задача состоит в том, чтобы вернуться к шагу 3, обнаружив, где проявляется ошибка. Также это именно тот случай, когда стоит использовать сторонние библиотеки для более тщательного логгирования.

Шаг 8: Исключите влияние железа или платформы

Замените оперативную память, жесткие диски, поменяйте сервер или рабочую станцию. Установите обновления, удалите обновления. Если ошибка пропадет, то причиной было железо, ОС или среда. Вы можете по желанию попробовать этот шаг раньше, так как неполадки в железе часто маскируют ошибки в ПО.

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

Ради интереса, переключите кабель питания в другую розетку или к другому ИБП. Безумно? Почему бы не попробовать?

Если у вас возникает одна и та же ошибка вне зависимости от среды, то она в вашем коде.

Шаг 9: Обратите внимание на совпадения

  1. Ошибка появляется всегда в одно и то же время? Проверьте задачи, выполняющиеся по расписанию.
  2. Ошибка всегда проявляется вместе с чем-то еще, насколько абсурдной ни была бы эта связь? Обращайте внимание на каждую деталь. На каждую. Например, проявляется ли ошибка, когда включен кондиционер? Возможно, из-за этого падает напряжение в сети, что вызывает странные эффекты в железе.
  3. Есть ли что-то общее у пользователей программы, даже не связанное с ПО? Например, географическое положение (так был найден легендарный баг с письмом за 500 миль).
  4. Ошибка проявляется, когда другой процесс забирает достаточно большое количество памяти или ресурсов процессора? (Я однажды нашел в этом причину раздражающей проблемы «no trusted connection» с SQL-сервером).

Шаг 10: Обратитесь в техподдержку

Наконец, пора попросить помощи у того, кто знает больше, чем вы. Для этого у вас должно быть хотя бы примерное понимание того, где находится ошибка — в железе, базе данных, компиляторе. Прежде чем писать письмо разработчикам, попробуйте задать вопрос на профильном форуме.

Ошибки есть в операционных системах, компиляторах, фреймворках и библиотеках, и ваша программа может быть действительно корректна. Но шансы привлечь внимание разработчика к этим ошибкам невелики, если вы не сможете предоставить подробный алгоритм их воспроизведения. Дружелюбный разработчик может помочь вам в этом, но чаще всего, если проблему сложно воспроизвести вас просто проигнорируют. К сожалению, это значит, что нужно приложить больше усилий при составлении багрепорта.

Полезные советы (когда ничего не помогает)

  1. Позовите кого-нибудь еще.
    Попросите коллегу поискать ошибку вместе с вами. Возможно, он заметит что-то, что вы упустили. Это можно сделать на любом этапе.
  2. Внимательно просмотрите код.
    Я часто нахожу ошибку, просто спокойно просматривая код с начала и прокручивая его в голове.
  3. Рассмотрите случаи, когда код работает, и сравните их с неработающими.
    Недавно я обнаружил ошибку, заключавшуюся в том, что когда вводимые данные в XML-формате содержали строку xsi:type=’xs:string’ , все ломалось, но если этой строки не было, все работало корректно. Оказалось, что дополнительный атрибут ломал механизм десериализации.
  4. Идите спать.
    Не бойтесь идти домой до того, как исправите ошибку. Ваши способности обратно пропорциональны вашей усталости. Вы просто потратите время и измотаете себя.
  5. Сделайте творческий перерыв.
    Творческий перерыв — это когда вы отвлекаетесь от задачи и переключаете внимание на другие вещи. Вы, возможно, замечали, что лучшие идеи приходят в голову в душе или по пути домой. Смена контекста иногда помогает. Сходите пообедать, посмотрите фильм, полистайте интернет или займитесь другой проблемой.
  6. Закройте глаза на некоторые симптомы и сообщения и попробуйте сначала.
    Некоторые баги могут влиять друг на друга. Драйвер для dial-up соединения в Windows 95 мог сообщать, что канал занят, при том что вы могли отчетливо слышать звук соединяющегося модема. Если вам приходится держать в голове слишком много симптомов, попробуйте сконцентрироваться только на одном. Исправьте или найдите его причину и переходите к следующему.
  7. Поиграйте в доктора Хауса (только без Викодина).
    Соберите всех коллег, ходите по кабинету с тростью, пишите симптомы на доске и бросайте язвительные комментарии. Раз это работает в сериалах, почему бы не попробовать?

Что вам точно не поможет

  1. Паника
    Не надо сразу палить из пушки по воробьям. Некоторые менеджеры начинают паниковать и сразу откатываться, перезагружать сервера и т. п. в надежде, что что-нибудь из этого исправит проблему. Это никогда не работает. Кроме того, это создает еще больше хаоса и увеличивает время, необходимое для поиска ошибки. Делайте только один шаг за раз. Изучите результат. Обдумайте его, а затем переходите к следующей гипотезе.
  2. «Хелп, плиииз!»
    Когда вы обращаетесь на форум за советом, вы как минимум должны уже выполнить шаг 3. Никто не захочет или не сможет вам помочь, если вы не предоставите подробное описание проблемы, включая информацию об ОС, железе и участок проблемного кода. Создавайте тему только тогда, когда можете все подробно описать, и придумайте информативное название для нее.
  3. Переход на личности
    Если вы думаете, что в ошибке виноват кто-то другой, постарайтесь по крайней мере говорить с ним вежливо. Оскорбления, крики и паника не помогут человеку решить проблему. Даже если у вас в команде не в почете демократия, крики и применение грубой силы не заставят исправления магическим образом появиться.

Ошибка, которую я недавно исправил

Это была загадочная проблема с дублирующимися именами генерируемых файлов. Дальнейшая проверка показала, что у файлов различное содержание. Это было странно, поскольку имена файлов включали дату и время создания в формате yyMMddhhmmss . Шаг 9, совпадения: первый файл был создан в полпятого утра, дубликат генерировался в полпятого вечера того же дня. Совпадение? Нет, поскольку hh в строке формата — это 12-часовой формат времени. Вот оно что! Поменял формат на yyMMddHHmmss , и ошибка исчезла.

Ошибка Microsoft Visual C++ Runtime Library. Как исправить?

Не так давно помогал одному хорошему знакомому с настройкой компьютера: у него при запуске любой игры выскакивала ошибка Microsoft Visual C++ Runtime Library… Так собственно и родилась тема этого поста: опишу в нем подробные шаги по восстановлению работоспособности ОС Windows и избавлению от этой ошибки.

Вообще, ошибка Microsoft Visual C++ Runtime Library может появиться по многим причинам и разобраться, порой, не так просто и быстро.

Типичный пример ошибки Microsoft Visual C++ Runtime Library.

1) Установка, обновление Microsoft Visual C++

Многие игры и программы были написаны в среде Microsoft Visual C++. Естественно, если у вас нет этого пакета, то игры работать не будут. Чтобы это исправить, нужно установить пакет Microsoft Visual C++ (кстати, распространяется бесплатно).

Ссылки на офиц. сайт Microsoft:

2) Проверка игры/приложения

Вторым шагом по устранению ошибок запуска приложений и игр — станет проверка и переустановка самих этих приложений. Дело в том, что возможно у вас были испорчены какие-нибудь системные файлы игры (dll, exe файлы). Причем, испортить могли как вы сами (случайно), так и например, «зловредные» программы: вирусы, трояны, рекламное ПО и пр. Часто банальная переустановка игры полностью избавляла от всех ошибок.

3) Проверка компьютера на вирусы

Многие пользователи ошибочно думают, что раз установлен какой-нибудь антивирус — значит никаких вирусных программ у них нет. На самом деле даже какое-нибудь рекламное ПО способно нанести определенный вред: замедлить работу компьютера, привести к появлению всевозможных ошибок.

Рекомендую проверить компьютер несколькими антивирусами, кроме этого ознакомиться с этими материалами:

4) NET Framework

NET Framework — программная платформа, на которой разрабатывают различные программы и приложения. Чтобы эти приложения могли запуститься, у вас на компьютере должна быть установлена требуемая версия NET Framework.

Все версии NET Framework + описание.

5) DirectX

Самая распространенная (по моим личным подсчетам) из-за чего происходит ошибка Runtime Library — это «самопальные» установки DirectX. Например, многие устанавливают на Windows XP 10-ю версию DirectX (в рунете на многих сайтах есть такая версия). Но официально XP не поддерживает 10-ю версию. В результате начинают сыпаться ошибки…

Рекомендую удалить через диспетчер задач (Пуск/панель управления/установка и удаления программ) DirectX 10, а затем произвести обновление DirectX через рекомендованный установщик от Microsoft (более подробно о вопросах с DirectX — см. в этой статье).

6) Драйвера на видеокарту

Обязательно проверьте драйвера на видеокарту, даже если до этого ошибок не наблюдалось.

1) Рекомендую проверить официальный сайт вашего производителя и скачать последнюю версию драйвера.

2) Затем удалить полностью старые драйвера из ОС, и установить новые.

3) Попробовать снова запустить «проблемную» игру/приложение.

PS

1) Некоторые пользователи заметили одну «незакономерную закономерность» — если у вас время и дата в компьютере не правильные (передвинуты сильно на будущее), то ошибка Microsoft Visual C++ Runtime Library может появляться и из-за этого. Дело в том, что разработчики программ ограничивают их срок использования, и, естественно, программы проверяя дату (видя что наступил крайний срок «X») — прекращают свою работу…

Исправить очень просто: установить реальную дату и время.

Ошибки в программе помогите исправить

Andersen1313

Препод сначала сказал что можно писать на любом Си. хоть Си++ хоть просто Си. написал на Си++(не без помощи конечно). Теперь он говорит что надо писать на Си..
Теперь пытаюсь исправить прогу на Си.. выдает много ошибок помогите разобраться.

[BCC32 Error] File1.c(41): E2451 Undefined symbol ‘new’
[BCC32 Error] File1.c(41): E2379 Statement missing ;

*Sl[sl] = new char[bufesize]; //Динамически выделим память для слова

[BCC32 Error] File1.c(67): E2451 Undefined symbol ‘new’
[BCC32 Error] File1.c(67): E2141 Declaration syntax error

*Sl[sl] = new char[bufesize]; //Динамически выделим память для слова

[BCC32 Error] File1.c(71): E2379 Statement missing ;

SlW[slw] = new char[width+1]; //Выделим память под строку размером ширина-колонки +1

[BCC32 Error] File1.c(95): E2109 Not an allowed type

SlW[slw] = new char[width+1]; //Выделим память под строку размером ширина-колонки +1

[BCC32 Error] File1.c(108): E2188 Expression syntax
[BCC32 Error] File1.c(108): E2451 Undefined symbol ‘m’
[BCC32 Error] File1.c(108): E2379 Statement missing ;

for (int m=0; m 0; j++) //Поставим наши разрывы, но с проверкой на отклонение

[BCC32 Error] File1.c(133): E2451 Undefined symbol ‘delete’
[BCC32 Error] File1.c(133): E2188 Expression syntax

Ошибка Microsoft Visual C++ Runtime Library: ее причины и решение

Всем доброго времени суток!

В подавляющем большинстве случаев, ошибка, связанная с Microsoft Visual C++, появляется при запуске различных игр (GTA San Andreas, Diablo III, WOW, WOT (танки) и т.д. — почему-то с этими играми больше всего обращаются за помощью) .

Вообще, Microsoft Visual C++ — это важный пакет, который позволяет запускать игры, в разработке которых была использована одноименная среда. Естественно, если данного пакета нет — игра у вас не запустится, вызвав ошибку. Кстати, ошибка может появиться и в тех случаях, когда есть проблемы с целостностью файлов одного из пакетов.

Причин проблем и ошибок, связанных Visual C++, довольно-таки много. В этой статье укажу на основные из них, и как можно их решить. Думаю, статья пригодится всем, кто столкнулся с данной проблемой.

Внешний вид ошибки / в качестве примера

Устранение причин ошибки Microsoft Visual C++ Runtime Library

1) Установка недостающего пакета Visual C++

Как правило ошибки, связанные с Visual C++, возникают из-за отсутствия определенного пакета (либо, из-за «кривой» установки оного). Поэтому, я бы порекомендовал первое, что сделать — это установить требуемый игрой пакет Visual C++ (о том, какой конкретно нужен, можно узнать в тех. требованиях игры (смотреть нужно либо в файле readme.txt, либо на официальном сайте игры) ).

Например, GTA V потребует следующих программных компонентов (это доп. требования к тех. характеристикам): Microsoft DirectX, Microsoft Visual C++ 2008, Google Chromium.

Ссылки представлены на оф. сайт Microsoft:

Microsoft Visual C++ 2010 (x64) — для ОС Windows 7; Server 2003 R2 x64; Server 2003 SP2; Server 2008 R2; Server 2008 SP2; Vista SP2; XP SP3;

Visual C++ для Visual Studio 2012 (обновление 4) — для ОС Windows 7 SP 1; 8; 8.1; Server 2003; Server 2008 R2 SP1; Server 2008 SP2; Server 2012; Vista SP2; XP.

Visual C++ для Visual Studio 2013 — для ОС Windows 7 SP1; 8; 8.1; Server 2003; Server 2008 R2 SP1; Server 2008 SP2; Server 2012; Server 2012 R2; Vista SP2; XP.

А здесь можете найти ссылки и скачать все последующие версии Visual C++ (которые могут появиться после выхода данной статьи в свет): https://support.microsoft.com/ru-ru/help/2977003/the-latest-supported-visual-c-downloads

Примечание:

  1. Первые версии Windows 7 и Windows XP не поддерживают Microsoft Visual C++ Redistributable 2012 и выше;
  2. Дистрибутивы для Windows x64, несовместимы с 32-разрядными ОС! Для тех, кто не знает, какая у него ОС, рекомендую вот эту статью: https://ocomp.info/kakaya-u-menya-windows.html

ДОПОЛНЕНИЕ!

Крайне рекомендую попробовать программу Driver Booster (ссылка выше). Она автоматически находит не только драйвера, но и необходимые компоненты, нужные для игр (в том числе и Visual C++), устанавливает их и устраняет причины ошибок. Рекомендую (скриншот ниже)!

Обратите внимание, что Driver Booster автоматически и сам находит все необходимые пакеты для устранения возможных проблем с играми!

2) Возможно нарушена целостность файлов игры (установщика)

Если переустановка компонентов Visual C++ и Driver Booster ничем не помогли, то рекомендую внимательно присмотреться к файлам установщикам самой игры. Многие ведь скачивают различные репаки, которые далеко от официальных релизов (часть файлов в них изменена, да и не всегда подобные релизы протестированы на десятках машин, чтобы избежать различных конфликтов и несовместимости).

Я бы порекомендовал загрузить новый установщик игры и переустановить ее. Перед этим не лишним будет прогнать систему на вирусы и рекламное ПО (нередко, когда вирусы портят системные файлы игры). О том, как лучше и чем проверить расскажу чуть ниже в статье.

Здесь же отмечу, что в 90% случаев проблем с ошибкой Microsoft Visual C++ Runtime Library — виноваты либо файлы самой игры, либо отсутствие нужных библиотек в системе. Т.е. первые две рекомендации в этой статье — это решение для большинства случаев!

3) Проверяем .NET Framework и DirectX

Помимо Visual C++, для игр в большинстве случаев, требуется обновленная версия DirectX и пакет .NET Framework. Если какого-то из этих пакетов нет (или его компоненты были повреждены), не исключены различные ошибки: то нет «DLL», то приложение не может быть продолжено, то «. Runtime Library. «.

У меня на блоге уже есть парочка статей, посвященных проблемам с .NET Framework и DirectX, рекомендую проверить эти пакеты:

https://ocomp.info/otsutstvie-d3dx9.html — Как обновить DirectX, а то не запускаются ни танки, ни любая другая игра

4) Проверяем и обновляем драйвер на видеокарту

У новых ОС Windows 8/10 есть одна особенность: они по умолчанию ставят максимальное количество драйверов, для всего оборудования, для которого могут. С одной стороны — это хорошо, сразу после установки системы с большинством оборудования можно уже работать, а с другой — они «усыпляют» бдительность.

Дело в том, что «такие» не родные драйвера, как правило, не обеспечивают полноценной поддержки всех функций (я уж не говорю, что помимо драйверов же, должны установиться различные центры управления).

Но так как у большинства пользователей все работает после инсталляции системы — то никто и не задумывается об этом до появления ошибок и конфликтов ПО. Поэтому, при появлении ошибок, связанных с Visual C++, в первую очередь, проверьте драйвер на видеокарту, от него сильно зависит работа игр.

Ниже привожу табличку с официальными сайтами для обновления драйверов видеокарты. Однако добавлю, что если у вас ноутбук — то в первую очередь проверьте офиц. сайт производителя вашего устройства. Дело в том, что производители ноутбуков часто оптимизируют свои драйвера для конкретных устройств!

Таблица №1: ссылки на официальные сайты для загрузки видеодрайверов.

Производитель Ссылка/описание
AMD

Есть два типа поиска и установки драйвера:

  1. можно загрузить и запустить спец. утилиту, которая определит какой нужен вам драйвер;
  2. а можно выбрать драйвер вручную, указав версию ОС и модель карты (об этом мы говорили выше).
NVIDIA

Можно автоматически определить какой нужен драйвер (на ПК должен быть установлен JAVA).

Можно вручную указать модель видеокарты и версию ОС.

Также на сайте доступны старые архивные версии драйверов, и бета-версии.

IntelHD

Здесь все просто: указываете версию ОС Windows, модельный ряд видеокарты и тип загружаемого файла: сайт автоматически находит вам самую оптимальную версию драйвера.

5) Проверка компьютера на вирусы и трояны, рекламное ПО

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

Поэтому, рекомендация простая: прогнать систему парочкой антивирусных утилит, которые порекомендую ниже. Если вирусы будут найдены и обезврежены — может потребоваться переустановка библиотеки Visual C++ (а также .NET Framework и DirectX).

  1. установить классический антивирус (если у вас нет) и прогнать им всю систему. Самые новые и лучшие из них на основе AV-теста, я приводил здесь: https://ocomp.info/antivirus-2020.html
  2. далее воспользоваться советами из статьи, рассказывающей про удаление вирусов, которые не видит обычный антивирус: https://ocomp.info/esli-antivirus-ne-vidit-virusov.html
  3. ну и, наконец, проверить систему одной из утилит по борьбе с рекламным ПО: https://ocomp.info/dlya-udaleniya-malware.html

К сожалению, универсальной программы, для решения и поиска всех вышеприведенные проблем, пока нет. Поэтому приходится пользоваться услугами нескольких приложений.

PS

В безнадежных случаях с Visual C++ — можно попробовать переустановить ОС Windows (я хоть и не сторонник подобного действа при каждой проблеме, однако, иногда проще и быстрее обойти стороной ошибку, чем найти ее причину ).

На этом всё. Всем удачи и поменьше ошибок!

Работа с кодом в Visual Studio Make code work in Visual Studio

Visual Studio включает эффективный интегрированный набор средств сборки и отладки проектов. Visual Studio provides a powerful integrated set of project build and debugging tools. Из этой статьи вы узнаете, как Visual Studio может помочь обнаружить проблемы в коде с помощью построения выходных данных, анализа кода, средств отладки и модульных тестов. In this article, find out how Visual Studio can help you find problems in your code using build output, code analysis, debugging tools, and unit tests.

Мы разобрались, как работать с редактором, и написали код. You’ve figured out the editor and created some code. Теперь необходимо убедиться, что код работает должным образом. Now, you want to make sure the code works properly. Отладка в Visual Studio, как и в большинстве интегрированных сред разработки (IDE), осуществляется в два этапа: построение кода для обнаружения и устранения ошибок проекта и компилятора и выполнение кода для обнаружения ошибок времени выполнения и динамических ошибок. In Visual Studio, as with most IDEs, there are two phases to making code work: building the code to catch and resolve project and compiler errors, and running the code to find run-time and dynamic errors.

Сборка кода Build your code

Существует два основных типа конфигурации сборки: отладка и выпуск. There are two basic types of build configuration: Debug and Release. При использовании конфигурации отладка создается более крупный и медленный исполняемый файл, обеспечивающий более широкие интерактивные возможности отладки во время выполнения. The Debug configuration produces a slower, larger executable that allows for a richer interactive run-time debugging experience. Исполняемый файл конфигурации отладка никогда не следует отправлять. The Debug executable should never be shipped. Конфигурация выпуск позволяет создать более быстрый оптимизированный исполняемый файл, подходящий для отправки (по крайней мере с точки зрения компилятора). The Release configuration builds a faster, optimized executable that’s appropriate to ship (at least from the perspective of the compiler). По умолчанию используется конфигурация Отладка. The default build configuration is Debug.

Самый простой способ выполнить сборку проекта — нажать клавишу F7, однако вы также можете начать сборку, выбрав в главном меню пункты Сборка > Собрать решение. The easiest way to build your project is to press F7, but you can also start the build by selecting Build > Build Solution from the main menu.

Процесс сборки можно наблюдать в окне Вывод в нижней части пользовательского интерфейса Visual Studio. You can observe the build process in the Output window at the bottom of the Visual Studio UI. Здесь отображаются ошибки, предупреждения и операции сборки. Errors, warnings, and build operations are displayed here. При наличии ошибок (или предупреждений выше заданного уровня) сборка завершится ошибкой. If you have errors (or if you have warnings above a configured level), your build fails. Можно щелкнуть ошибку и предупреждение, чтобы перейти к строке, где они возникли. You can click on the errors and warnings to go to the line where they occurred. Для перестроения проекта можно нажать клавишу F7 (чтобы перекомпилировать только файлы с ошибками) или CTRL+ALT+F7 (для чистого полного перестроения). Rebuild your project by either pressing F7 again (to recompile only the files with errors) or Ctrl+Alt+F7 (for a clean and complete rebuild).

В окне результатов содержатся два окна с вкладками под областью редактора: окно Вывод, в котором содержатся необработанные выходные данные компилятора (включая сообщения об ошибках), и окно Список ошибок, содержащее список всех ошибок и предупреждений, к которому можно применить сортировку и фильтры. There are two tabbed windows in the results window below the editor: the Output window, which contains the raw compiler output (including error messages); and the Error List window, which provides a sortable and filterable list of all errors and warnings.

После успешного выполнения построения вы увидите примерно следующие результаты в окне Вывод: When build succeeds, you see results like this in the Output window:

Просмотр списка ошибок Review the Error List

Если вы внесли какие-либо изменения в код, который был ранее и успешно скомпилирован, возможно, возникнет ошибка. Unless you’ve made no modifications to code you’ve previously and successfully compiled, you probably have an error. Если вы новичок в написании кода, возможно, их будет много. If you’re new to coding, you probably have lots of them. Ошибки иногда очевидны, например простая синтаксическая ошибка или неправильное имя переменной, а иногда их причину трудно выяснить, имея в распоряжении только зашифрованный код. Errors are sometimes obvious, such as a simple syntax error or incorrect variable name, and sometimes they are difficult to understand, with only a cryptic code to guide you. Чтобы получить более четкое представление о проблеме, перейдите вниз окна Вывод сборки и щелкните вкладку Список ошибок. При этом вы перейдете к более организованному представлению ошибок и предупреждений для проекта и получите доступ к некоторым дополнительным параметрам. For a cleaner view of the issues, navigate to the bottom of the build Output window, and click the Error List tab. This takes you to a more organized view of the errors and warnings for your project, and gives you some extra options as well.

Щелкните строку ошибки в окне Список ошибок, чтобы перейти в строку кода, в которой возникла ошибка. Click on the error line in the Error List window to jump to the line the error occurs in. (Кроме того, номера строк можно включить, нажав клавиши Ctrl+Q, введя номера строк, а затем выбрав Включить или отключить отображение номеров строкв результатах. (Or turn on line numbers by pressing Ctrl+Q, typing line numbers, and then choosing Turn line numbers on or off from the results. Это самый быстрый способ перехода в диалоговое окно Параметры, где можно включить номера строк. This is the fastest way to get to the Options dialog where you can turn on line numbers.)

Нажмите клавиши CTRL+G для быстрого перехода к номеру строки, в которой возникла ошибка. Press Ctrl+G to quickly jump to the line number where the error occurred.

Ошибку можно узнать по подчеркиванию красной волнистой линией The error is identified by a red «squiggle» underscore. Чтобы получить дополнительные сведения, наведите на нее указатель мыши. Hover over it for additional details. Внесите исправления, и подчеркивание исчезнет, хотя в результате исправления может возникнуть новая ошибка Make the fix and it will go away, although you may introduce a new error with the correction. (это называется «регрессия»). (This is called a «regression».)


Пройдите список ошибок и устраните все ошибки в коде. Walk through the error list and address all the errors in your code.

Просмотр подробных сведений об ошибках Review errors in detail

Многие ошибки трудны для восприятия, будучи представленными в терминах компилятора. Many errors may make no sense to you, phrased as they are in the terms of the compiler. В этом случае могут потребоваться дополнительные сведения. In those cases, you’ll need additional information. Из окна Список ошибок можно выполнить автоматический поиск в поисковой системе Bing для получения дополнительных сведений об ошибке или предупреждении. From the Error List window, you can do an automatic Bing search for more information on the error or warning. Щелкните правой кнопкой мыши по соответствующей строке записи и выберите Показать справочные сведения об ошибке из контекстного меню или щелкните гиперссылку с кодом ошибки в столбце код в списке ошибок. Right-click on the corresponding entry line and select Show Error Help from the context menu, or click on the hyperlinked error code value in the Code column of the Error List.

В зависимости от настроек результаты поиска по коду и описанию ошибки откроются в веб-браузере либо во вкладке Visual Studio с результатами поиска Bing. Depending on your settings, either your web browser displays the search results for the error code and text, or a tab opens inside Visual Studio and shows the results of the Bing search. Представленные результаты — из различных источников в Интернете, и, возможно, не все они будут полезными. The results are from many different sources on the Internet, and not all may be helpful.

Анализ кода Use code analysis

Средства анализа выполняют поиск общих проблем в коде, которые могут привести к ошибкам времени выполнения или проблемам управления кодом. Code analyzers look for common code problems that can lead to run-time errors or problems in code management.

Анализ кода C# и Visual Basic C# and Visual Basic code analysis

Visual Studio содержит встроенный набор анализаторов платформы компиляторов .NET, которые проверяют код на C# и Visual Basic при его наборе. Visual Studio includes a built-in set of .NET Compiler Platform analyzers that examine C# and Visual Basic code as you type. Можно установить дополнительные анализаторы в виде расширений Visual Studio или в виде пакетов NuGet. You can install additional analyzers as a Visual Studio extension, or as a NuGet package. При обнаружении нарушений правил они помечаются как в списке ошибок, так и в редакторе кода (волнистая линия под соответствующим кодом). If rule violations are found, they are reported both in the Error List and in the code editor as a squiggle under the offending code.

Анализ кода C++ C++ code analysis

Чтобы выполнить анализ кода C++, запустите статический анализ кода. To analyze C++ code, run static code analysis. Запустить этот компонент после устранения всех очевидных ошибок, препятствующих успешной сборке, и потратить некоторое время, чтобы устранить создаваемые им предупреждения, — очень полезная привычка. Get in the habit of running it once you’ve cleaned up the obvious errors that prevent a successful build, and take some time to address the warnings it may produce. Вы сможете избавиться от определенных будущих проблем, а также научитесь некоторым полезным приемам написания кода. You’ll save yourself some headaches down the road, and you may learn a few code style techniques.

Нажмите клавиши ALT+F11 (или выберите в верхнем меню команду Анализ > Выполнить анализ кода в решении) для запуска статического анализа кода. Press Alt+F11 (or select Analyze > Run Code Analysis on Solution from the top menu) to start static code analysis.

Все новые или обновленные предупреждения отображаются на вкладке Список ошибок в нижней части интегрированной среды разработки. Any new or updated warnings appear in the Error List tab at the bottom of the IDE. Щелкните предупреждение для перехода к нему в коде. Click on the warnings to jump to them in code.

Использование быстрых действий для исправления или рефакторинга кода Use Quick Actions to fix or refactor code

Быстрые действия, доступные с помощью значка лампочки или отвертки, позволяют выполнить встроенный рефакторинг кода. Quick Actions, available from the light bulb or screwdriver icon, let you refactor code inline. Это простой способ быстрого и эффективного устранения распространенных предупреждений в коде C#, C++ и Visual Basic. They are an easy way to fix common warnings quickly and effectively in C#, C++, and Visual Basic code. Для доступа к ним щелкните правой кнопкой мыши волнистую линию предупреждения и выберите Быстрые действия и рефакторинг. To access them, right-click on a warning squiggle and select Quick Actions and refactorings. Либо, когда курсор находится на строке с цветной волнистой линией, нажмите клавиши CTRL+ . Or, when your cursor is on the line with the colored squiggle, press Ctrl+. или выберите значок отвертки, лампочки или лампочки с ошибкой на поле. or select the light bulb, error light bulb, or screwdriver icon in the margin. Вы увидите список возможных исправлений или операций рефакторинга, которые можно применить к соответствующей строке кода. You’ll see a list of possible fixes or refactorings you can apply to that line of code.

Быстрые действия можно использовать в любом случае, когда средство анализа кода определяет возможность исправления, рефакторинга или улучшения кода. Quick Actions can be used wherever code analyzers determine there’s an opportunity to fix, refactor, or improve your code. Щелкните любую строку кода, откройте контекстное меню и выберите пункт Быстрые действия и рефакторинг. Click on any line of code, right-click to open the context menu, and select Quick Actions and refactorings. Если доступны варианты рефакторинга или улучшения, то они будут отображены. If refactoring or improvement options are available, they are displayed. В противном случае в левом нижнем углу интегрированной среды разработки появится сообщение Быстрые действия недоступны. Otherwise, the message No quick actions available here displays in the lower-left corner of the IDE.

Если вы привыкли работать с клавиатурой, вы можете использовать клавиши со стрелками и сочетание клавиш CTRL+ . With experience, you can quickly use the arrow keys and Ctrl+. для проверки возможностей оптимизации и очистки кода! to check for easy refactoring opportunities and clean up your code!

Запуск очистки кода Run Code Cleanup

В Visual Studio можно по запросу форматировать файл кода C#, в том числе параметры стиля кода, с помощью кнопки Очистка кода в нижней части редактора. Visual Studio provides on-demand formatting of your C# code file, including code style preferences, through the Code Cleanup button at the bottom of the editor.

Помимо форматирования пробелов, отступов и т. п., функция Очистка кода применяет определенные вами соглашения о стиле кода. In addition to formatting your file for spaces, indents, et cetera, Code Cleanup also applies a set of code style conventions that you define. Ваши настройки для каждого стиля кода считываются из файла EditorConfig, если такой существует в проекте, или из раздела Параметры стиля кода, который доступен через диалоговое окно Параметры. Your preferences for each code style are read from the EditorConfig file, if you have one for the project, or from the code style settings in the Options dialog box.

Отладка выполняемого кода Debug your running code

Успешно завершив сборку кода и его очистку, запустите код, нажав клавишу F5 или выбрав команду Отладка > Начать отладку. Now that you’ve successfully built your code and performed a little clean up, run it by pressing F5 or selecting Debug > Start Debugging. Приложение будет запущено в среде отладки, и вы сможете пронаблюдать его поведение. This starts your app in a debug environment so you can observe its behavior in detail. Интегрированная среда разработки Visual Studio изменяется во время выполнения приложения: окно Вывод заменяется двумя новыми окнами (в конфигурации окон по умолчанию): окном с вкладками Видимые/Локальные/Контрольные значения и окном с вкладками Стек вызовов/Точки останова/Параметры исключений/Вывод. The Visual Studio IDE changes while your app is running: the Output window is replaced by two new ones (in the default window configuration), the Autos/Locals/Watch tabbed window and the Call Stack/Breakpoints/Exception Settings/Output tabbed window. Эти окна имеют несколько вкладок, которые позволяют просмотреть и проверить переменные, потоки, стеки вызовов приложения и другие характеристики поведения во время выполнения приложения. These windows have multiple tabs that allow you to inspect and evaluate your app’s variables, threads, call stacks, and various other behaviors as it runs.

Остановите приложение, нажав клавиши SHIFT+F5 или кнопку Остановить. Stop your app by pressing Shift+F5 or by clicking the Stop button. Кроме того, можно просто закрыть главное окно приложения (или диалоговое окно командной строки). Or, you can just close the app’s main window (or command-line dialog).

Если код выполняется полностью и точно так, как ожидалось, вас можно поздравить. If your code ran perfectly and exactly as expected, congratulations! Но в случае зависания, сбоя или непредвиденных результатов может потребоваться найти источник проблем и исправить ошибки. However, if it hung, or crashed, or gave you some strange results, you’ll need to find the source of those problems and fix the bugs.

Задание простых точек останова Set simple breakpoints

Точки останова — это один из самых простых и важных компонентов надежной отладки. Breakpoints are the most basic and essential feature of reliable debugging. Точка останова указывает, где Visual Studio следует приостановить выполнение кода, чтобы вы могли проверить значения переменных или поведение памяти либо выполнение ветви кода. A breakpoint indicates where Visual Studio should suspend your running code so you can take a look at the values of variables, or the behavior of memory, or whether or not a branch of code is getting run. После установки или удаления точек останова перестраивать проект не нужно. You don’t need to rebuild a project after setting and removing breakpoints.

Установите точку останова, щелкнув дальнее поле строки, в которой требуется приостановить выполнение, или нажмите клавишу F9, чтобы установить точку останова в текущей строке кода. Set a breakpoint by clicking in the far margin of the line where you want the break to occur, or press F9 to set a breakpoint on the current line of code. Выполнение кода прерывается (останавливается) перед инструкциями для этой строки кода. When you run your code, it will pause (or break) before the instructions for this line of code are executed.

Чаще всего точки останова используются для решения следующих задач. Common uses for breakpoints include:

Для сужения области поиска источника сбоя или зависания, когда точки останова устанавливаются в разных местах участка кода вызова метода, который, возможно, является источником проблемы, и за его пределами. To narrow down the source of a crash or hang, scatter breakpoints throughout and around the code of the method call you think is causing the failure. При выполнении кода в отладчике удаляйте, а затем снова устанавливайте точки останова ближе друг к другу, пока не найдете строку кода, вызывающую ошибку. As you run code in the debugger, remove and then reset the breakpoints closer together until you find the offending line of code. Выполнение кода в отладчике описывается в следующем разделе. See the next section to learn how to run code in the debugger.

При добавлении нового кода установите точку останова в его начале и выполните код, чтобы убедиться в том, что он работает правильно. When you introduce new code, set a breakpoint at the beginning of it, and run the code to make sure it is behaving as expected.

При реализации сложного поведения задайте точки останова для алгоритмического кода, чтобы можно было проверить значения переменных и данные при прерывании программы. If you’ve implemented a complicated behavior, set breakpoints for the algorithmic code so you can inspect the values of the variables and data when the program breaks.

При написании кода C или C++ используйте точки останова для остановки кода, чтобы можно было проверить значения адреса (ищите значение NULL) и просмотреть значения счетчиков при отладке ошибок, связанных с памятью. If you’re writing C or C++ code, use breakpoints to stop the code so you can inspect address values (look for NULL) and reference counts when debugging for memory-related failures.

Дополнительные сведения о точках останова см. в статье Использование точек останова. For more information about using breakpoints, read Using breakpoints.

Проверка кода во время выполнения Inspect your code at run-time

Когда выполнение кода приостанавливается из-за достижения точки останова, строка кода, помеченная желтым цветом (текущий оператор), еще не выполнена. When your running code hits a breakpoint and pauses, the line of code marked in yellow (the current statement) has not executed yet. Вы можете выполнить текущий оператор и проверить, как изменились значения. At this point, you may want to execute the current statement and then inspect the changed values. Для выполнения кода в отладчике можно использовать ряд команд пошагового выполнения. You can use several step commands to execute code in the debugger. Если отмеченный код является вызовом метода, вы можете выполнить шаг с заходом, нажав клавишу F11. If the marked code is a method call, you can step into it by pressing F11. Кроме того, можно выполнить шаг с обходом строки кода, нажав клавишу F10. You can also step over the line of code by pressing F10. Дополнительные команды и подробные сведения о пошаговом выполнении кода см. в статье Навигация по коду с помощью отладчика. For additional commands and details on how to step through code, read Navigate code with the debugger.

Код, представленный на предыдущей иллюстрации, может выполняться отладчиком по одному оператору. Для этого можно нажимать клавишу F10 или F11 (так как здесь нет вызова метода, результат выполнения обеих команд будет одинаковым). In the preceding illustration, you can advance the debugger one statement by pressing either F10 or F11 (since there is no method call here, both commands have the same result).

Когда отладчик приостанавливает выполнение, можно проверить переменные и стеки вызовов, чтобы разобраться в происходящем. While the debugger is paused, you can inspect your variables and call stacks to determine what is going on. Находятся ли значения в тех диапазонах, которые вы ожидали увидеть? Are the values in the ranges you expect to see? Выполняются ли вызовы в правильном порядке? Are calls being made in the right order?

Наведите курсор на переменную для просмотра ее текущего значения и ссылок. Hover over a variable to see its current value and references. Если отображается значение, которое вы не ожидали увидеть, возможно, в предыдущем или вызывающем коде имеется ошибка. If you see a value you didn’t expect, you probably have a bug in the preceding or calling code. Более подробные сведения об отладке см. в статье об использовании отладчика. For more in-depth debugging information, learn more about using the debugger.

Кроме того, Visual Studio выводит на экран окно средств диагностики, где можно наблюдать за загрузкой ЦП и использованием памяти приложением в динамике по времени. Additionally, Visual Studio displays the Diagnostic Tools window, where you can observe your app’s CPU and memory usage over time. В дальнейшем в процессе разработки приложения эти средства можно применять для выявления случаев непредвиденно высокой загрузки ЦП или чрезмерного выделения памяти. Later in your app development, you can use these tools to look for unanticipated heavy CPU usage or memory allocation. Это окно можно использовать в сочетании с окном Контрольные значения и точками останова, чтобы определить причину непредвиденно интенсивного использования или неосвобожденных ресурсов. Use it in conjunction with the Watch window and breakpoints to determine what’s causing unexpected heavy usage or unreleased resources. Дополнительные сведения см. в статье Обзор возможностей профилирования. For more information, see Profiling feature tour.

Запуск модульных тестов Run unit tests

Модульные тесты — это первая линия защиты от ошибок в коде, так как при правильном проведении они позволяют проверять отдельные «модули» кода (как правило, это отдельные функции), которые проще отлаживать, чем всю программу. Unit tests are your first line of defense against code bugs because, when done correctly, they test a single «unit» of code, typically a single function, and are easier to debug than your full program. Visual Studio устанавливает платформу модульного тестирования Майкрософт для управляемого и машинного кода. Visual Studio installs the Microsoft unit testing frameworks for both managed and native code. Платформа модульного тестирования используется для создания модульных тестов, их запуска и передачи результатов таких тестов. Use a unit testing framework to create unit tests, run them, and report the results of these tests. Завершив внесение изменений, запустите модульные тесты повторно, чтобы убедиться, что код по-прежнему работает правильно. Rerun unit tests when you make changes, to test that your code is still working correctly. При использовании выпуска Visual Studio Enterprise можно настроить автоматический запуск тестов после каждой сборки. With Visual Studio Enterprise edition, you can run tests automatically after every build.

Чтобы приступить к работе с модульными тестами, ознакомьтесь со статьей Создание модульных тестов для кода с помощью IntelliTest. To get started, read Generate unit tests for your code with IntelliTest.

Дополнительные сведения о модульных тестах в Visual Studio, а также о том, как они могут помочь в создании более качественного кода, см. в статье Основные сведения о модульных тестах. To learn more about unit tests in Visual Studio and how they can help you create better quality code, read Unit test basics.

C++ — Помогите исправить ошибку в программе

БлогNot. Типичные ошибки начинающего разработчика на C++: проблемы и их решения

Типичные ошибки начинающего разработчика на C++: проблемы и их решения

сейчас в списке: 61 ошибка Проводя гораздо больше времени, чем мне хотелось бы, за разного рода учебными мероприятиями по программированию, я поневоле начал собирать коллекцию типовых ошибок, допускаемых начинающими разработчиками. Попробую приспособить для неё эту запись, надеюсь, список постепенно будет пополняться. до 50-60 самых типовых проблем, ну, уж никак не больше 100 :)

Конечно, я не ставлю цели рассказывать обо всех возможных синтаксических ошибках — для этого есть компилятор. Я обращу внимание скорее на типовые алгоритмические и логические неточности, допускаемые начинающими. Весь приведённый код проверен, в основном, для этого служили бесплатные сборки Microsoft Visual C++ версии 2010 или выше.

Страница длинная, поэтому воспользуйтесь оглавлением или нажмите комбинацию клавиш Ctrl+F для поиска нужного текста на странице.

Оглавление
Попытка модифицировать константный указатель

Ошибка особенно коварна тем, что всплывёт на этапе исполнения программы:

а при компиляции всё может выглядеть нормально.

Первый способ исправления — выделять память под s динамически:

Второй способ — заменить исходный указатель массивом.

Некоторые компиляторы, например, от Borland, выполняют и исходный код. Это их проблемы, а в стандарте языка такого нет.

К тому же виду ошибки можно отнести и такое:

Так нельзя, в s нет столько места, и после ввода строки возникнет ошибка. Правильно было бы сделать константный указатель на изменяемую строку, указав её размер сразу:

Теперь ввод в s будет работать, если не указывать вторым параметром метода getline размерность, большую количества выделенной памяти (255 байт в нашем случае).

Ещё правильнее выделить новую память, а затем её освободить:

Двойная перестановка элементов массива

Ошибка встречается при транспонировании матрицы, инверсии (переворчивании) символов строки и т.п. Суть дела в том, что вы применяете полные циклы там, где нужны только их «половинки» :)

Пример: перевернём символы строки правильно.

Типичная ошибка: при верхней границе цикла, равной L , строка останется неизменённой, так как каждая пара символов будет переставлена дважды.

Пример: транспонирование матрицы.

Типичная ошибка: если сделать в main полный двойной цикл

то ничего транспонировано не будет.

Пример: сравнить попарно все элементы вектора (программа только напечатает номера пар сравниваемых элементов)

Типовая ошибка: если сделать полный двойной цикл

то сравнения будут выполняться дважды, более того, каждый элемент будет сравниваться «сам с собой».

Пример. Меняем местами максимальные и минимальные элементы массива. Неверно:

После оператора, помеченного «1», бывший максимум уже заменён минимальным значением. Идущий следом второй оператор меняет всё обратно. Правильно, например, так:

Окно программы закрывается, я не успеваю увидеть результаты работы программы?

Если Вы не программировали остановки в программе, её и не будет!

Вставляйте оператор, ожидающий ввода с клавиатуры перед оператором return главной функции.

Варианты такого кода:

Неправильный кастинг (приведение типов)

Как известно, C++ допускает преобразования типов данных с потерей точности, в этом случае компилятор может просто «промолчать» или сгенерировать предупреждение:

Для таких случаев вполне подойдёт static_cast :

Все скобки — и треугольные, и круглые, здесь обязательны!

Если же компилятор выдаёт ошибку преобразования типа, например, при попытке присваивания структур разных типов

то можно рискнуть применить

— но лишь потому, что мы понимаем, что структуры type1 и type2 на самом деле полностью совместимы по типам данных, хотя и имеют разные теги имени структурного типа и разные наименования полей:

Обратите внимание, что присваивание через указатель var2 , как и положено, изменит значение поля исходной переменной var1 .

= вместо == (присваивание вместо сравнения)

Головная боль начинающих, особенно после Паскаля :)

Компилятор не найдёт в этом никаких проблем, максимум, сгенерирует предупреждение. Меж тем, переменной i будет присваиваться «двойка», а так как результат этой операции равен true , то всегда будет выполняться ветвь 1.

Решение очевидно — пишите правильно операцию сравнения, а именно, ==

& и | вместо && и || (побитовые операции вместо логических)

Первый оператор выполнит логическое умножение над отдельными битами значений n1 и n2 , так что для младшего байта получится

Второй оператор каждую переменную приведёт к типу bool , так что true && true = true (напомню, что true считаются все ненулевые значения).

Второй оператор мог бы быть более наглядно выполнен условием вида n1!=0 && n2!=0

Неверное использование char как int

Вот этот код ошибочно интерпретирует значение c как число (а не код символа), пытаясь прибавить к нему значение 10. В результате получится отнюдь не 11, а 59, то есть символ » ; «

Происходит это потому, что код символа «ноль» равен 48, а «единицы» 49. Правильным решением было бы сначала отнять от символа-цифры код нуля, равный 48. Неявно используется предположение, что цифровые символы закодированы идущими подряд числовыми значениями (это так во всех распространённых кодировках).

Неверное выделение/освобождение динамической памяти

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

1. Вся динамически выделяемая память должна освобождаться, в идеале «по принципу стека», то есть, занявший память последним объект освобождает её первым:

2. Если память выделялась через new , она освобождается через delete , если через new[] — через delete[] , то есть, последним оператором нужно освобождать память от массивов:

3. Не смешивайте в одной программе разные способы выделения и освобождения памяти. Если вы выделяете память с помощью функции malloc или calloc , то освобождайте её с помощью функции free , при выделении через операторы new/new[] , освобождайте с помощью delete/delete[] . В целом использование в проектах C++ «сишных» функций malloc , calloc и free не одобряется стандартом.

4. Бойтесь повторных delete , применённых к уже удалённым объектам — это одна из самых трудноуловимых ошибок. Для многих компиляторов действует неформальный «хак» — явно занулять указатель после delete , присваивая ему 0 или NULL , что зависит от компилятора:

Теперь повторные delete не опасны.

5. По возможности избегайте выделения памяти на одном уровне (например, в теле функции), а освобождения — на другом (например, в функции main ). Даже если речь о «куче» и операторах new / delete . Например:

При вызове функции f в неё передаётся копия указателя Ptr . При выделении памяти адрес помещается в эту копию, то есть, значение переменной Ptr не изменится. После возврата из функции адрес потеряется, соответственно, потеряется выделенная память и возникнет ошибка времени выполнения. Как вариант, можно делать так:

(передавать в функцию адрес указателя) или так:

(принимать в функции ссылку на указатель), но всё равно выглядит вычурно :)

Возврат из функции ссылки или указателя на локальную переменную

Да, если вам повезёт, эти 2 функции вернут результаты 1 и 2 соответственно:

На самом деле, так поступать нельзя. Локальные переменные, созданные в стеке, уничтожаются при выходе из их области видимости (в нашем случае — при выходе из функции). Таким образом, память получает статус свободной и туда могут быть записаны какие-либо новые данные. Если это не успело произойти, Вы свои 1 и 2 получите. но в сложном коде почти гарантированно однажды произойдёт сбой. Чтобы не попасть впросак, используйте естественное

Функция good2 имеет смысл в предположении, что оператор new выделяет память в куче (heap), а под локальные объекты память выделяется в стеке (stack). Также потенциально опасно, если память выделяется на одном уровне вложенности кода, а освобождается на другом.

Та же проблема имеется и с возвратом локальных строк:

Самый естественный способ исправить — в функцию передавать буфер, куда копируем строку. По возможности, при всех операциях с буфером нужно контролировать возможный выход за его границу, особенно когда работаем с заранее неизвестными размерами (типовое и не лучшее решение — использование strncpy вместо strcpy внутри функции f ).

Использование неинициализированных переменных

. то есть, вы делаете что-то с переменной, которая просто описана, но не получала никакого значения:

Результат может быть любым — от генерации ошибки времени исполнения до неверного расчёта, сделанного программой. Особенно часто забывают давать начальное значение количеству, сумме, максимуму или минимуму, демонстрируя тем самым, что типовые алгоритмы не учили :)

Пока мы не начали суммировать элементы массива, переменная-сумма sum отнюдь не обязана быть равной нулю!

Нулями автоматически инициализируются только:

  • статические переменные, описанные с указанием ключевого слова static ;
  • в некоторых компиляторах — глобальные переменные, описанные вне всех функций (полагаться не стоит);
  • динамические области памяти, выделяемые устаревшей сишной функцией calloc .

Два добрых совета, экономящих кучу времени:

1. Привыкнуть инициализировать объявленные переменные всегда. А указатели тоже инициализировать значением 0 или NULL (да ещё и сбрасывать обратно в эти значения после освобождения динамической памяти, связанной с указателем).

2. Объявлять переменные как можно ближе к месту их использования, благо, C++ это позволяет.

Пустой цикл из-за точки с запятой.

Часто ставят лишнюю точку с запятой, например, после открывающей части цикла:

Результат выполнения этого кода будет поистине страшен! Во-первых, здесь не написано «суммировать n элементов массива a «. Здесь написано » n раз выполнить пустой цикл, а затем прибавить к переменной sum значение i -го элемента массива a «. Во-вторых, после выхода из цикла по i , значение этой переменной может оказаться равным 3 , что приведёт ещё и к выходу за границы массива при выполнении a[i] .

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

Чтобы не совершать этой глупой ошибки, помните — точка с запятой завершает действие (цикл, объявление, оператор), а не начинает его.

Функция main не имеет типа int

Вроде бы и не ошибка, но. распространённейшее

— неверно. Согласно стандарту, функция main() должна возвращать целочисленное значение, правильно вот так:

Определение структурного типа или класса не заканчивается точкой с запятой

Вот эта маленькая программа сгенерирует, как минимум, 3 ошибки:

То же самое и при объявлении классов — не забывайте про символ ; в конце.

В нашем примере можно было и сразу же описать структурный тип и определить структуру:

Сравнение вещественных значений как целых

Проблема возникает при сравнении вещественных значений a , b в виде

Дело в том, что арифметические вычисления для чисел с плавающей запятой выполняются с некоторой погрешностью, обусловленной тем, что хранить все знаки дробной части числа в памяти бывает невозможно, например, 2/3=0.66666666666. — ряд шестёрок неизбежно будет где-то обрезан.

Правильный путь — сравнивать вещественные числа с некоторой точностью, которая зависит от поставленной задачи, например

Аналогичная проблема возникает в циклах с вещественной управляющей переменной, скажем, в этом цикле

переменная x рискует «потерять» своё последнее значение, равное 1 , всё из-за тех же погрешностей. Правильный путь — прибавлять к правой границе диапазона изменения x некое малое значение, заведомо меньшее шага: for (x=0; x char ) с помощью операций отношения , == , >= и т.д. — глубоко неправильное для C++ действие. Так мы будем сравнивать не содержимое, а указатели (адреса памяти, где начинаются строки). Правильный путь — стандартная функция сравнения строк strcmp (подключить заголовки string.h ).

Неправильная запись чисел

Да-да, такое тоже бывает. Например, посмотрите, что напечатает этот код:

Просто лидирующий ноль означает число в восьмеричной системе счисления. Добавлять ноль перед числом не нужно никогда. Перед строкой — пожалуйста:

Вторая «детская» проблема, способная, тем не менее, создать жуткий головняк — применение запятой вместо точки для отделения дробной части вещественного числа.

Правило — всегда использовать точку, а не запятую при записи чисел! C++ — не Microsoft Office, а средство его написания :)

В длинных математических выражениях ошибка очень трудноуловима. Максимум, что скажет компилятор — предупреждение о неиспользуемой переменной при включённом флаге -Wunused-value . Поэтому программирование математики должно быть особенно тщательным.

Принадлежит ли значение интервалу?

Проверка, которая выполняется очень часто. Допустим, есть переменная x , нужно проверить, попадает ли её значение в интервал [a,b] . Единственный правильный путь сделать это — записать

Самые распространённые неправильные способы записи собраны, некоторые из них даже компилируются, но это ничего не значит :)

Так как операция сравнения левоассоциативна (выполняется слева направо), это эквивалентно записи

дающей истинный результат при любом a .

Тоже истина для любого x .

Результатом операции «запятая» является последнее выражение, то есть, здесь проверяется только условие x

Неверный составной условный оператор

Проблема возникает, когда вы хотите запрограммировать более 2 вариантов расчёта. Обычно всё дело — в непонимании того, как работает условный оператор с несколькими ветвями расчёта.

Вот простейший пример, здесь мы определяем знак z целого числа a , по правилу:

Вот типичная ошибка такого расчёта:

Применение одного короткого и одного полного условных операторов является здесь грубой ошибкой — ведь после завершения короткого условного оператора для всех ненулевых значений a будет выполнено присваивание z=1 . Правильных вариантов этого расчета, по меньше мере, два:

— с помощью 3 коротких условных операторов, вариант не очень хорош тем, что проверяет лишние условия даже тогда, когда знак уже найден.

— с помощью составного условного оператора, этот вариант лучше.

Вторая типичная проблема — неправильный порядок ветвей в составном операторе, из-за которого некоторые условия срабатывают «досрочно» или не срабатывают вовсе. Например, в показанном ниже фрагменте, где нужно было вывести, является ли значение x чётным или нечётным и отдельно учесть значение x=12 , напечатав для него слово «Дюжина», эта самая «дюжина» не будет напечатана никогда:

Проблема в том, что значение 12 — тоже чётное, и сработавшая ветвь «Чётное» не даст сработать ветви «Дюжина». Да и проверка условий организована явно избыточно, правильно было так:

Чтобы не допускать таких ошибок, нужно понимать, как работает составной условный оператор. Его общий вид может включать произвольное число условий и ветвей расчета:

При использовании оператора последовательно проверяются условия 1, 2, . ,N , если некоторое условие истинно, то выполняется соответствующий оператор и управление передается на оператор, следующий за условным. Если все условия ложны, выполняется ветвь0 , если она задана, или не выполняется ни одной ветви, если ветвь0 отсутствует. Число ветвей N не ограничено. Существенно то, что если выполняется более одного условия из N , обработано всё равно будет только первое истинное условие.

Функция не возвращает значения всегда или в некоторых случаях

Если функция не имеет тип void , она должна возвращать значение указанного в заголовке типа при любых комбинациях своих входных параметров. Например, следующая функция

ошибочна: для нулевого или отрицательного значения x возвращаемое значение отсутствует.

Простейший способ избежать проблемы — всегда возвращать из функции некое «значение по умолчанию»:

Некоторые компиляторы, например, Visual Studio, могут предупредить об этой проблеме:

Но для этого надо установить соответствующий уровень предупреждений компилятора. В Visual Studio это делается через команду меню Проект, Свойства, Свойства конфигурации, С/С++, Общие, Уровень предупреждений, Уровень 4. По умолчанию принят уровень 3.


Не срабатывает останов в программе или «не работает» оператор ввода

Очень частая проблема. Например, почти во всех компиляторах второй ввод через scanf будет пропущен:

А вот в таком виде всё сработает верно:

В ряде компиляторов могут быть проблемы и с таким кодом:

На самом деле, всё очень просто. «Проскакивание» ожидания ввода (паузы) происходит из-за того, что в потоке после предшествующего ввода остаются символы. Чаще всего остаётся символ новой строки \n , который попадает в поток при нажатии Enter. Оператор cin >> его просто проигнорирует, а такие функции, как getchar() , cin.get() и т.п. считывают его как первый символ в потоке и код идёт дальше, а ожидания ввода символа не происходит. Резюме — перед применением этих функций поток нужно очищать — fflush (stdin) на С или cin.sync() на C++

Вот в этом коде, если не повезёт, могут быть проблемы:

А в этом — вряд ли:

Удобней всего просто синхронизировать поток перед операциями ввода:

Экзотика. Вместо cin.get() можно просто пропустить символы:

Можно также в цикле прочитать оставшиеся символы

Выход за границы массива

Индексы массивов в C++ начинаются с нуля. Для массива из n элементов допустимые индексы лежат в диапазоне [0..n-1] . Чтение или запись информации вне выделенной памяти приводит к неопределенному поведению программы.

Приведённая ниже ошибка, скорей всего, сравнительно безобидна, а вот запись элемента в несуществующий элемент массива способна привести к краху программы.

Со строками данная ошибка обусловлена, чаще всего, отсутствием в них нуль-терминатора (байта с кодом 0, пишется ‘\0’, не путать с цифрой 0 (‘0’), имеющей код 48!)

Переключатель switch без операторов break

Если проверяемая величина принимает заранее известный фиксированный набор значений, оператор-переключатель удобнее, чем составной условный. Но если забыть про то, что каждую ветвь case нужно завершать оператором break , позволяющим выйти из переключателя, результаты могут быть плачевны:

Здесь для i , равного 0 , будет выведено zero one other . При i , равном 1 , будет выведено one other . То есть, без break происходит «проваливание» к следующей метке.

Бывает, что отсутствие break — не баг, а фича. Например, вот эта функция умеет возвращать 1-ю, 2-ю или 3-ю степень «двойки», а в остальных случаях результат будет равен единице.

Просто укажите комментарием, если break вам не нужны и ветви переключателя должны «проваливаться».

Градусы вместо радианов у тригонометрических функций

Очень часто к неожиданным результатам расчётов приводят вот такие ляпы в коде: Получится значение x = 0.893997, а отнюдь не 1. Просто человек имел в виду 90 градусов, а компьютер принимает аргументы тригонометрических функций в радианах. Если входная величина задана в градусах, переведите её в радианы:

Ещё лучше написать маленькую функцию, делающую такой перевод.

Неверный вызов конструктора базового класса из конструктора производного

В показанном ниже коде производный класс B пытается воспользоваться конструктором своего родителя A .

Правильный способ — использовать списки инициализации в конструкторе потомка.

Сравнение знаковых и беззнаковых значений

Вот в этом коде -1 «неожиданно» окажется больше 1:

Знаковое x приводится к беззнаковому, отчего возрастает до значения UINT_MAX — 1 (само UINT_MAX равно max(unsigned int)-1 , в разных компиляторах может обозначаться разными именами).

Решение — не сравнивать знаковые и беззнаковые значения, заранее приводя их к одному типу данных.

Вызов виртуального метода из конструктора класса

Класс A хочет для инициализации свойства x воспользоваться виртуальным методом f :

У класса-потомка B виртуальный метод реализован, но всё равно ничего не выходит. Проблема в том, что при создании объекта B , сначала создается базовая часть (класс A ), а в конструкторе базового класса ничего о классе B ещё не известно, поскольку он еще не создан, в том числе, не заполнена таблица виртуальных функций.

Решение: не вызывать виртуальные методы из конструкторов.

Неправильное выделение тела цикла или ветви условного оператора

Если в теле цикла находится более одного оператора, его следует заключать в фигурные операторные скобки.

Если же повторяемый оператор всего один, допустима запись тела как с операторными скобками, так и без них:

К сожалению, начинающие разработчики часто путаются и не ставят операторных скобок даже если в цикле больше одного оператора. Получается вот что:

Оператор вывода cout не имеет отношения к циклу, в цикле находится только оператор a[i]= , а выравнивание отступами для компилятора С++ ничего не значит.

Делать его всё равно нужно, это облегчает чтение программы человеком

Для исправления ошибки достаточно заключить тело цикла в операторные скобки:

Аналогичная проблема характерна и для ветвей условных операторов. Вот в этом коде

несмотря на визуальное выравнивание, ветка else относится не к первому if , а ко второму, скобки же способны решить проблему и показать разветвление кода наглядно:

Без указания дополнительных операторных скобок else всегда относится к ближайшему сверху if, для которого ветка else ещё не указана

Самый простой способ не запутаться — всегда ставить операторные скобки после ключевых слов for , while , do , if , else if или else и закрывать открытые скобки сразу же, так, чтобы закрывающая скобка была непосредственно под открывающей

или же под первой буквой ключевого слова, к которому относится открывающая скобка:

В любом случае, код, помещённый внутри цикла или ветви алгоритма сдвигается вправо пробелами и выравнивается, так что одному уровню вложенности всегда соответствует одинаковое число пробелов. Я лично для скорости печати обхожусь одним, но часто испольуют несколько пробелов или табуляцию, тем более, что в современных редакторах кода этот параметр легко настраивается. В частности, в Visual C++ пройдите в меню Сервис, Параметры, Текстовый редактор, C/C++, Табуляция и настройте так, как вам удобно.

Функция не может узнать размер параметра-массива

Функция f неудачно пытается воспользоваться конструкцией sizeof для определения размера массива-параметра:

Решение 1, самое простое и верное, подходит и для статических, и для динамических массивов. Передать размерность массива как параметр функции.

Решение 2, только для статического массива. Размер статического массива можно узнать, если принять в функции ссылку на массив и использовать template для типа данных. Увы, это сработает не во всех компиляторах и обратная совместимость кода с Си нарушается.

Решение 3, тоже подойдёт для статического массива, но не сработает с динамическим, память под который выделялась оператором new . Размер массива можно задать при использовании шаблона, вот образец:

Но это уже совсем жутик по сравнению с универсальным и обладающим обратной совместимостью способом 1 :)

Неверный порядок свойств класса при использовании списка инициализации

Есть класс со свойствами x и y , проинициализируем их с использованием списка в конструкторе:

Проблема состоит в том, что в списке инициализации конструктора объекты инициализируются в том порядке, в котором они объявлены в классе или структуре, а не в том, который указан в списке инициализации. В нашем случае сначала будет проинициализирована переменная x , а только потом y , что приведёт к неопределённости значения x .

Выход — следить за порядком объявления переменных в классе.

Функция работает с локальной копией объекта вместо объекта

Представим, что мы написали пару функций для удобной инициализации динамического массива и его удаления из памяти:

Показанный код в корне неверен тем, что при вызове функции init_array в нее передается копия указателя a , описанного в главной функции. Этот указатель ещё не проинициализирован на момент вызова функции. При выделении памяти, адрес массива будет помещён в локальную копию a внутри функции, значение a в функции main от этого не изменится. Соответственно, после выхода из функции выделенная память будет потеряна.

Первый способ решения — передать в функцию адрес указателя, используя конструкцию ** :

Второй способ — принимать в функции ссылку на указатель, конструкцию *& :

Это удобнее, не так ли? :)

Наконец, вот такая версия программы тоже способна отработать успешно —

Несоблюдение правила Большой Тройки при разработке класса или структуры

Правило Большой Тройки состоит вот в чём: если класс или структура определяет любой из следующих трёх методов:

  1. Деструктор
  2. Конструктор копирования
  3. Оператор присваивания

то он должен определить и два остальных метода! По меньшей мере, если в классе идёт работа с памятью, её динамическое выделение!

В любом случае, эти три метода — особые члены класса и будут созданы компилятором автоматически. Но наверняка автоматически созданные версии не удовлетворят потребности класса, например, по копированию объектов или освобождению ранее выделенной памяти. Приведём классический пример класса-массива, в котором хранится его размерность, а память выделяется динамически.

В рассмотренном случае конструктор по умолчанию тоже не создается автоматически.

Чтение данных «в никуда»

В основном, этим грешат начинающие при использовании scanf , забывая, что ей нужно передавать адрес переменной:

Выведется бред или возникнет Runtime Error. Правильно так:

Использование указателя как массива

Гораздо чаще, чем хотелось бы, приходится видеть в коде такое:

Конечно, так нельзя — предварительно выделите память под a. Указатель — только переменная, предназначенная для хранения адреса памяти, места под элементы массива там нет! Правильно, например, так:

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

Перепутаны символ char и строка char *

Отдельный символ (величина типа char ) не есть строка символов, заданная указателем на тип char ( char * )

Скорее уж char похож на целое число int , представляя собой код символа.

При работе с однобайтовыми кодировками char занимает 1 байт памяти.

Строка char * занимает столько байт, сколько в ней символов, плюс ещё один, необходимый для хранения нуль-терминатора — байта с кодом ноль, записываемого как ‘\0’ . Не путать с цифрой ‘0’ , имеющей код 48 !

Вот практический пример. Во избежание синтаксической ошибки «находчивый» новичок явно преобразовал тип char к char * при вызове стандартного метода strcat . Всё, что он получил — Runtime-ошибку «Нарушение прав доступа».

Правильным путём было либо «присобачить» символ к строке «вручную», не забыв про нуль-терминатор:

либо создать массив из 2 символов и тогда уже использовать strcat :

Разумеется, всё это имеет смысл при условии, что в str есть «свободное место», зарезервированное статически или выделенное динамически.

Забыли, что в строке всегда должен быть нуль-терминатор

. и предусмотрен дополнительный символ (байт) для него. Вот этот код в Visual Studio вполне способен привести к краху программы.

Деструктор базового класса должен быть виртуальным!

Вот здесь я приводил эту великую мысль как пример типичной сиплюсплюснутой заумности :) Но что поделать, если это действительно так. Посмотрим простейшую иерархию из родителя A и потомка B , конструкторы и деструкторы которых печатают в консоль факт своего вызова:

Эта программа напечатает: A()B()

То есть, деструктор класса B не вызывался, соответственно, он мог не освободить память, если таковая выделялась конструктором!

Изменив деструктор класса A на

получим вывод A()B()

Таким образом, виртуальный деструктор нужен для правильного полиморфного удаления объектов.

Во избежание проблем всегда следует как минимум:

1. При наличии хотя бы одного виртуального метода объявлять виртуальным и деструктор.

2. Также его надо явно объявлять виртуальным, если класс предполагается в будущем сделать базовым.

Вызов функции, изменяющей некие величины, стоит в одном операторе с изменёнными величинами

Приведём пример простой программы, справа от операторов вывода написано, что печатается.

Как видим, обе функции успешно меняют то, что должны изменить: init — свои параметры, переданные по ссылке, а init2 — глобальную переменную global .

Но попытка вывести изменённые функциями значения в одном операторе с вызовом функций оба раза оказалась безуспешна.

Проблема в том, что до точки с запятой (конца текущего оператора) значения остаются в рамках одной инструкции и не меняются.

Также никогда нельзя рассчитывать на то, что вычисление значений аргументов в списке параметров функции выполняется слева направо.

Ссылка или указатель на «переехавший» объект

На словах эту распространённую проблему можно описать так:

1. В динамический объект с лимитом памяти, например, в вектор, добавляются объекты (элементы) по значению.

2. В какой-то момент запоминается ссылка или указатель на какое-либо из значений вектора.

3. В вектор добавляют ещё некоторое количество объектов.

4. В какой то момент резерв памяти иссякает, и вектор делает realloc , то есть, расширяет буфер, перенося туда свои объекты. В результате объекты меняют адрес.

5. Ранее выданные «наружу» ссылки или указатели становятся недействительными, но программа никак не отследит это.

6. Обращение по неверному указателю или ссылке приводит к ошибке времени исполнения и краху программы. Ну или просто к потере указателя, если читаем данные.

Ошибка очень трудноуловима, потому что «авария» может произойти очень далеко от места причины. Для вектора часто резервируют память ( vector::reserve ) и обычно её хватает. а однажды, при каких-то сочетаниях исходных данных, не хватит.

Совсем простой пример без векторов и классов:

Вывод — не полагаться на ссылку (указатель) на объект, являющийся элементом некой динамической структуры данных.

Неверный вызов конструктора по умолчанию

В показанном ниже коде программист хотел создать объект a класса A и написал круглые скобки для указания того, что нужен конструктор без параметров:

Но эта конструкция была проинтерпретирована как объявление прототипа функции без параметров с именем a , которая возвращает значение типа A .

Правильным было бы объявление

Неявный вызов конструктора по умолчанию базового класса вместо его конструктора копирования

При копировании объектов вместо конструктора копии, у базового класса запускается конструктор по умолчанию. Вот код примера:

Проблема состоит в том, что при наследовании конструктор копирования не будет порождать вызов конструктора копирования базового класса. Программист должен явно указать, какой базовый конструктор нужно запустить. А компилятор запускает только «конструкторы по умолчанию». Правильно было бы заменить строчку

Изменение управляющей переменной цикла в теле цикла

Глупая ошибка, но встречается очень часто, вот она в немного утрированном виде:

Всего лишь помним — внутри цикла for его управляющая переменная не должна меняться иначе, чем в заголовке цикла. Для циклов do .. while и while . do счётчик меняйте всегда последним оператором тела цикла, тогда не возникнет ошибок.

Повторное вычисление границ цикла

Проблема, часто замедляющая быстродействие программы. Цикл for создавался для выполнения заранее известного числа шагов. Не надо заставлять его вычислять это число шагов заново на каждом шаге:

У меня это выполнилось в среднем за 0.875 ms, на каждом шаге заново вычислялись верхняя граница цикла и шаг. Исправим отмеченную комментариями // часть на

и стабильно получим заметно меньшее время. В книгах и инете распространён миф, что компилятор самостоятельно умеет оптимизировать расчёты в условии цикла.

Это не совсем так. В общем случае, компилятор может оптимизировать только константы в условии цикла. Но у меня здесь не произошло и этого. Внешнюю переменную в границе цикла компилятор тем более не будет оптимизировать, как раз потому, что в теле цикла эта переменная может быть изменена.

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

А вот если вы пользуетесь готовой и адекватной реализацией контейнера, она сама сделает подстановку нового размера. В показанном ниже коде перебор элементов вектора выполняется с помощью итератора i , верхняя граница изменения которого «каждый раз вычисляется заново» методом end :

Равноценна по времени исполнения будет замена выделенного комментариями // цикла на

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

Неверный итератор после изменения контейнера внутри цикла

Посмотрим на наполнение выделенного комментариями // цикла for .

Синтаксически вполне корректный, он приведёт к краху программы. Дело в том, что после удаления элемента, итератор i начинает ссылаться на несуществующий элемент и становится невалидным. Следующее i++ уже делается «к ничему» и приводит к краху.

Типовое неверное исправление могло бы быть таким:

Останется крах при размерности списка, кратной 3, то есть, предполагающей удаление последнего элемента. То есть, ошибка станет ещё трудноуловимей. А всё дело в том, что метод erase присваивает итератору ссылку на элемент, идущий следом за удаляемым. А за удаляемым последним ничего нет, и опять инкремент ведёт за разрешённую область памяти.

Правильно будет так:

Обратите внимание, что в заголовке цикла for теперь не делается «автоматического» шага.

Можно было сделать и

Почему? Различия в работе префискного и постфиксного инкрементов, которые нужно хорошо понимать.

Неверный #define с параметрами

Вот пример для этой распространённой проблемы:

Директива #define в этой программе неверна. И ответы будут разные, причём, верен второй, полученный без #define . Дело в том, что макрос — это совсем не функция, а только чисто синтаксическая подстановка, SQUARE(x+1) превратится в x+1 * x+1 или, с учётом старшинства операций, x + x +1 .

Всегда берите аргументы #define в круглые скобки!

На всякий случай, следует избегать и строчных комментариев // при определении #define , хотя современные компиляторы обычно справляются:

А вот всё тело макроса тоже лучше всегда брать в круглые скобки, иначе выйдет вот что:

А вот так всё правильно:

Типичной проблемой является также наличие пробела между именем макроса и открывающей скобкой при описании директивы #define . Это неправильно, открывающая скобка должна идти «впритык» к имени макроса.

Вот так всё правильно:

Объявление и инициализация переменной в ветви case

Нельзя одновременно объявлять и инициализировать переменную в ветви case . Можно поместить ветвь оператора switch в операторные скобки < . >, но это чревато другими ошибками.

Объявляя переменную в одном блоке case , вы делаете её доступной для всех последующих case . Если засунуть в < . >, то область видимости ограничится фигурными скобками.

Компилятор не всегда «увидит» такую ошибку, более того, ряд компиляторов вообще не найдёт проблем в приведённом коде, но это не значит, что так нужно делать.

Несоблюдение отступов в тексте программы

Само по себе не является ошибкой, но создаёт для начинающих массу проблем, основная из которых на C++ — «потерянные» операторные скобки, порождающие кучу самых невероятных ошибок от компилятора.

Чтобы не попасть впросак и не терять времени, всегда соблюдайте несколько несложных правил.

1. Структурируйте и выравнивайте код, чтобы сделать его читаемым. Суть в том, что блоки закрываются скобкой > в том же столбце текстового редактора, в котором они открыты скобкой < . Существует, по меньшей мере, два осмысленных способа сделать это:

Мне лично нравится второй, так как экономит мне одно нажатие Enter и минимум одно нажатие пробела (если редактор текста не понимает автоматических отступов). Закрывающая скобка находится не под открывающей, но под первом символом открывающего блок оператора — это воспринимается как то же самое, стоит Вам написать 10-20 тысяч строк кода. Этот стиль неизменен практически во всех моих листингах.

Что касается количества пробелов в отступах, здесь вкусы тоже разнятся. Мне лично нравится одно нажатие пробела, как самое экономичное:

Мне не нравится также использование символа табуляции для отступа. В большинстве встроенных в IDE редакторов размер отступа табуляции невелик, скажем, равен 4, а в «простых» текстовых редакторах, вроде Блокнота, встроенного редактора Far или Notepad++, в которых тоже приходится открывать листинги, он классически равен 8. В результате программа «разъезжается» далеко вправо на сложных блоках, а вид текста зависит от размера отступа табуляции.

Поэтому в том же Visual Studio я делаю так: меню Сервис — Параметры — Все языки — Табуляция, Отступы = Блок (тогда курсор выравнивает следующую строку по предыдущей), Размер интервала табуляции и Размер отступа = 1, выбрана опция Вставлять пробелы.

2. Для соблюдения правила 1 любые блоки всегда закрывайте сразу. Такой блок, как

пишется сразу, а только потом ветвь алгоритма или тело цикла наполняются содержимым. Это поможет не запутаться в сложном коде и облегчит соблюдение следующего принципа.

3. Если делать всё правильно, некомпилируемый код никогда не остаётся «на завтра». Блочно-модульная структура программы позволяет всегда избежать этого. Подпрограмма может быть пустой «заглушкой», вы можете использовать ничего не делающие условия, пустые блоки, комментарии, но текущий код должен компилироваться, если завтра вы не хотите половину рабочего дня затратить на восстановление в памяти недоделанного сегодня.


4. В редакторе кода используется только моноширинный шрифт, как в старых консолях или современном Studio (загляните в меню Сервис — Параметры — Среда — Шрифты и цвета). Без этого все рассуждения об отступах теряют смысл.

«Неожиданный» результат деления целых чисел

Несмотря на её банальность, проблема встречается довольно часто.

Деление целых в C++ даёт целое, забывать об этом нельзя. Правильно так:

То есть, применяем один из способов:

  • хотя бы один из аргументов превратить в вещественный тип, добавив к числу символ точки;
  • явно привести хотя бы один из аргументов к вещественному типу оператором (float)a или (double)a .
Посимвольное чтение файла обрывается при достижении буквы ‘я’

Проблема не в букве ‘я’, а в байте со значением 255. Именно это значение, рассмотренное, как char ( 0xff ) и приведённое к типу int ( 0xffffffff ) совпадёт со значением EOF , которое равно -1 . При работе под Windows с файлами в кодировке Windows-1251 код номер 255 имеет русская буква ‘я’ маленькая. В других кодировках этому коду может соответствовать другая буква. Пример неверного кода:

Решение — изменить тип переменной c :

Использование strncpy без добавления нуль-терминатора

Стандартная функция strncpy часто используется для «безопасного» копирования строк — её третий аргумент задаёт «максимальное количество символов» (на самом деле, длину буфера).

Проблема в том, что функция «забывает» ставить нуль-терминатор в конец целевой строки:

Правильно было бы поставить перед printf «ручное» завершение строки:

Сама по себе реализация этой функции такова: если исходная строка короче целевого буфера, то strncpy будет заполнять всю хвостовую часть оставшегося буфера нулями. Если строка длиннее целевого буфера, strncpy забудет выполнить её нуль-терминацию. Увы, адекватной замены методу копирования ограниченного количества символов в стандарте нет. Есть strlcpy , но это только для unix-систем.

Обяснение проблемы такое: изначально strncpy предназначалась для перевода обычных нуль-терминированных строк в строки фиксированной ширины.

Строки фиксированной ширины использовались в файловой системе Unix.

В формате фиксированной ширины строка хранится в соответствии со следующими правилами:

  • Все строки хранятся в буфере заранее заданной фиксированной ширины N;
  • Если строка имеет длину меньше N, то все лишние позиции в строке заполняются нулевыми символами;
  • Если строка имеет длину ровно N, то она полностью заполняет буфер и не заканчивается нулевым символом.
Функции atoi/atof или sscanf для перевода строки в число

Указанные функции очень популярны при преобразованиях строки в число. Тем не менее, есть 2 серьёзных проблемы, связанных с ними:

  • они не формируют отчёта об ошибочных ситуациях;
  • они имеют неопределённое поведение при переполнении.

Покажем это на примере:

Стандарт рекомендует использовать для преобразования строк в числа функции группы strto. : strtol , strtoul , strtod . Они умеют сообщать в вызывающий код о неправильном формате входных данных и устойчивы к переполнению, при котором сообщают о нём через стандартную переменную errno :

Кроме того, любую некорректную запись числа atoi / atof считают нулём.

Применение delete к объекту из стека

Вот маленькая программа, на которой хорошо видна проблема:

Суть дела в том, что оператор new выделяет память в «куче» (heap) — см. объект c . Тогда применим и delete .

Объект d создаётся в стеке ( stack ), к нему delete неприменим. Хотя при создании объекта строкой кода

конструктор будет вызван.

Каждому способу выделения памяти для переменой соответствует свой способ освобождения, например

Следует учесть, что при выделении памяти через malloc конструктор не вызывается.

Отметим также, что если для объекта, расположенного в стеке, конструктор выделяет память под какие-либо поля — например, в классе есть поле

а конструктор выделяет для него память

то в классе всё равно пишется деструктор и в нём должен быть delete[] для name . Деструктор в этом случае вызовется автоматически в конце области видимости. Нужно проектировать программу так, чтобы подобный вызов был к месту.

Если же время жизни объекта нужно контролировать независимо от текущей области видимости и освобождать его директивно, явным вызовом деструктора, то такой объект следует размещать в «куче» и выделять память оператором new .

Наконец, в классе можно создать метод с условным именем erase , который закроет все внутренние объекты и освободит занимаемую ими память. Деструктор просто вызывает метод erase , но erase можно вызвать и без деструктора.

См. также в этой заметке про стек и кучу.

Пути к файлам без двойного бэкслеша

Очень частая проблема у начинающих, особенно, если они «пришли» с другого, не си-подобного языка:

В этой программе файл никогда не будет открыт и прочитан, даже если он существует и содержит данные. Дело в том, что обратный слеш внутри двойных кавчек для C и C++ — спецсимвол, например, \t означает табуляцию, а \n — перевод строки. Если внутри двойных кавчек нужен символ «обратный слэш», как известно, служащий в Windows для разделения имён папок при записи пути к файлам, он удваивается: \\.

Поэтому правильно будет так:

«Удвоение» последней строки файла

Возьмём небольшую программу, построчно читающую текстовый файл:

Сам файл C:\temp\data.txt состоит из пары строк и пустой строки в конце:

«Удивительным образом» наша программа «удвоит» string 2 , которая будет напечатана дважды. Проблема в том, что после чтения string 2 конец файла ещё не достигнут, а ввод-вывод через stdio буферизован. последний шаг цикла прочитает пустую строку, а в буфере всё ещё будет string 2 , которая и выведется повторно вместо пустой строки. Проверьте сами — если удалить из файла данных пустую строку в конце —

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

(лучше посмотреть здесь про чтение чисел scanf’ом из файла со «смешанным» форматом).

Что же до нашего исходного примера — всегда полезен дополнительный анализ прочитанных строк (например, исключение из вывода пустых) или хоть зануление буфера после того, как он использован:

«Лишние» пустые строки при построчном выводе данных

С программкой из этого примера связана ещё одна типовая проблема — прочитанные из файла строки при выводе почему-то содержат лишние пустые строки между строками данных. Файл данных: Вывод:

Всё объясняется просто — fgets читает строку файла вместе с символом перевода строки (точней, под Windows — с парой символов \r\n , интерпретируемых как один), а puts добавляет к выводимой строке ещё один перевод строки. Так что выводите другим методом или удаляйте из прочитанной fgets ‘ом строки последний символ:

Переопределённый оператор не возвращает экземпляр или ссылку на экземпляр класса

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

Оператор += изменяет только текущий объект, но тоже может встретиться в цепочке вычислений, скажем, A d=*a+=*b; Вполне достаточно, если он вернёт *this для возможности выполнения дальнейших расчётов.

А вот бинарному сложению после выполнения *a + *b нужно вернуть именно новый объект класса, чтобы можно было, например, продолжить цепочку вычисления, прибавив той же функцией-оператором ещё c : *a + *b + c .

Формально не запрещено, сделать и такое бинарное сложение:

Но выражение над экземплярами класса *a + *b + с работать уже не будет, только *a + *b .

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

Из текстового файла по формату читается только первое число и всё зацикливается!

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

если файл data.txt в текущей папке вот такой:

(прочитается только первое число).

Решение — либо убрать русскую локаль, для которой разделитель целой и дробной части числа — не точка, а запятая:

(закомментировали оператор), либо в файле заменить . в числах на ,

Если читать средствами C++ (потоки), а Си-совместимыми — аналогично.

Сцепление Си-строк без выделения памяти

Сначала воспроизведем типичную ошибку начинающих:

Так как функция strcat не выделяет память, поведение такого кода непредсказуемо и с вероятностью 99% приведёт к ошибке времени исполнения программы! А вот такое сцепление строк сработает:

То есть, всегда должна быть память, куда писать — статическая из буфера или выделенная динамически самой программой.

Из той же оперы — использование указателя как массива. Не забывайте также, что вместо динамических массивов и строк Си практичнее использовать контейнер vector и класс string.

Неверное использование тернарного оператора

Тернарный условный оператор (conditional expression) вида условие?оператор1:оператор2; очень удобен, но способен создать ряд проблем при неаккуратном его применении.

При работе с ним нужно учесть 2 момента.

Во-первых, типом тернарного оператора будет наиболее общий тип его двух последних операндов. Что значит наиболее общий? Например, для int и short общим типом будет int , то есть, наиболее общий тип — это такой тип, к которому могу быть приведены оба операнда.

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

Кроме того, если в тернарном операторе происходит преобразование типов к наиболее общему, то тернарный оператор является rvalue . Если же нет, то lvalue (что это значит?).

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

Например, вот эта маленькая программа корректно использует тернарный оператор для вывода пробела или перевода строки в cout (массив печатается по 2 элемента в одной строке консоли):

Без дополнительных скобок в операторе вывода, то есть, при коде

вывод будет воспринят как

и окажется неправильным.

Присваивание объектов класса, содержащих динамические свойства, без написания конструктора копирования

Если в классе есть динамическое свойство, заданное указателем, при копировании объекта класса, под который выделялась динамическая память в «куче», скопируется только адрес памяти, содержащийся в указателе.

Если затем объект 2, бывший справа от знака «=», будет удалён, перестанет работать и ссылка на память из объекта 1:

Для корректной работы нужно опеределить в классе оператор присваивания и конструктор копирования (см. правило большой тройки).

Тогда можно переписать динамическое свойство s в новую память, которую мы выделим в куче (код простейший, не содержит проверок того, удалось ли выделить память):

«Опасная» проверка булевой переменной в условии

Безобидное на первый взгляд

может привести к трудноуловимой ошибке. Например, в ряде компиляторов константа true==-1 , а в C++ принято, что всё, что не 0 , равно true и только 0 — это false .

Соответственно, всегда безопасней

Неверное выделение памяти под динамическую матрицу

Отметим как отдельную ошибку. Правильный путь таков:

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

Освобождать память, в идеале, нужно в порядке, обратном выделению. Вот пример кода.

12.02.2015, 12:38; рейтинг: 81210

Ошибки в программах си

Ошибки в программах си

В этой статье мы разберем основные синтактические ошибки в программах си, научимся искать их в программе и исправлять. Наиболее частые ошибки в программах c++ си
Пропустили после оператора знак точка с запятой;
Забыли объявить переменную
Неправильно указали имя оператора
Забыли поставить открывающую или закрывающую фигурную скобку < или >в условных или циклических операторах или в процедурах
Ошибка в программе си Пропустили после оператора знак точка с запятой;
На примере простейшей программы на си разберем эту ошибку
#include
#include
main()
<
printf(«Hello world!») //забыли точку с запятой
getch(); // ждем нажатия любой кнопки
>
При запуске программы в нижнем окне мы увидим сообщение об ошибке в программе си
expected `;’ before «getch» Т.е. если видим фразу expected `;’ значит мы пропустили ;
Красным цветом будет выделено место ошибки.

Компилятор нам указывает пропущено ; до getch
Ищем в программе это место и ставим ; после оператора си
printf(«Hello world!»);
Ошибка в программе си забыли объявить переменную
На примере программы на си сложения двух чисел разберем эту ошибку
#include
#include
main()
<
int b;// забыли объявить переменную a
int c;
a=10;
b=20;
c=a+b;
printf(«%d+%d= %d», a,b,c);
getch();
>
При запуске программы окно ошибок выдаст
`a’ undeclared (first use this function)
Т.е. если мы видим фразу undeclared, значит мы пропустили объявление переменной.

Мы должны подняться наверх программы или функции, где используется переменная и объявить переменную.
int a;
Ошибка в программе си Неправильно указали имя оператора
На примере простейшей программы на си разберем эту ошибку
#include
#include
main()
<
pritf(«Hello world!»); //неправильно указан оператор printf
getch(); // ждем нажатия любой кнопки
>
При запуске этой программы компилятор выдаст
`pritf’ undeclared (first use this function)
И красным цветом выделит в программе си место ошибки
Если мы видим `слово’ undeclared, то значит либо мы неправильно написали оператор, либо используем не объявленную переменную. Мы должны перейти на красную строку в программе си, где ошибка и исправить оператор на правильный
printf(«Hello world!»);
Ошибка в программе си Забыли поставить открывающую или закрывающую фигурную скобку
На примере программы на си поиска максимального из трех чисел разберем эту ошибку

#include
#include
main()
<
float a,b,c, max;
printf(«введите первое число «);
scanf(«%f», &a);
printf(«введите второе число «);
scanf(«%f», &b);
printf(«введите третье число «);
scanf(«%f», &c);
max=a;
if (b>max)
<
max=b; // забыли поставить закрывающую скобку
if (c>max)
<
max=c;
>
printf(«максимальное число %f», max);
getch();
>
При запуске этой программы на си, компилятор выдаст ошибку
expected `>’ at end of input.

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

Ошибки в программах си

Ошибки в программах си

В этой статье мы разберем основные синтактические ошибки в программах си, научимся искать их в программе и исправлять. Наиболее частые ошибки в программах c++ си
Пропустили после оператора знак точка с запятой;
Забыли объявить переменную
Неправильно указали имя оператора
Забыли поставить открывающую или закрывающую фигурную скобку < или >в условных или циклических операторах или в процедурах
Ошибка в программе си Пропустили после оператора знак точка с запятой;
На примере простейшей программы на си разберем эту ошибку
#include
#include
main()
<
printf(«Hello world!») //забыли точку с запятой
getch(); // ждем нажатия любой кнопки
>
При запуске программы в нижнем окне мы увидим сообщение об ошибке в программе си
expected `;’ before «getch» Т.е. если видим фразу expected `;’ значит мы пропустили ;
Красным цветом будет выделено место ошибки.

Компилятор нам указывает пропущено ; до getch
Ищем в программе это место и ставим ; после оператора си
printf(«Hello world!»);
Ошибка в программе си забыли объявить переменную
На примере программы на си сложения двух чисел разберем эту ошибку
#include
#include
main()
<
int b;// забыли объявить переменную a
int c;
a=10;
b=20;
c=a+b;
printf(«%d+%d= %d», a,b,c);
getch();
>
При запуске программы окно ошибок выдаст
`a’ undeclared (first use this function)
Т.е. если мы видим фразу undeclared, значит мы пропустили объявление переменной.

Мы должны подняться наверх программы или функции, где используется переменная и объявить переменную.
int a;
Ошибка в программе си Неправильно указали имя оператора
На примере простейшей программы на си разберем эту ошибку
#include
#include
main()
<
pritf(«Hello world!»); //неправильно указан оператор printf
getch(); // ждем нажатия любой кнопки
>
При запуске этой программы компилятор выдаст
`pritf’ undeclared (first use this function)
И красным цветом выделит в программе си место ошибки
Если мы видим `слово’ undeclared, то значит либо мы неправильно написали оператор, либо используем не объявленную переменную. Мы должны перейти на красную строку в программе си, где ошибка и исправить оператор на правильный
printf(«Hello world!»);
Ошибка в программе си Забыли поставить открывающую или закрывающую фигурную скобку
На примере программы на си поиска максимального из трех чисел разберем эту ошибку

#include
#include
main()
<
float a,b,c, max;
printf(«введите первое число «);
scanf(«%f», &a);
printf(«введите второе число «);
scanf(«%f», &b);
printf(«введите третье число «);
scanf(«%f», &c);
max=a;
if (b>max)
<
max=b; // забыли поставить закрывающую скобку
if (c>max)
<
max=c;
>
printf(«максимальное число %f», max);
getch();
>
При запуске этой программы на си, компилятор выдаст ошибку
expected `>’ at end of input.

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

Урок №7. Решения самых распространенных проблем

Обновл. 21 Фев 2020 |

В этом уроке мы рассмотрим наиболее частые проблемы, с которыми сталкиваются новички в C++.

Проблема №1

Как использовать русский язык в программах C++?

Ответ №1

Чтобы выводить кириллицу в C++ нужно подключить заголовочный файл Windows.h:

И прописать следующие две строчки в функции main():

Проблема №2

При выполнении программы появляется чёрное консольное окно, а затем сразу пропадает.

Ответ №2

Некоторые компиляторы (например, Bloodshed’s Dev C++) автоматически не задерживают консольное окно после того, как программа завершила своё выполнение. Если проблема в компиляторе, то следующие два шага решат эту проблему:

Во-первых, добавьте следующую строчку кода в верхнюю часть вашей программы:

Во-вторых, добавьте следующий код в конец функции main() (прямо перед оператором return):

Таким образом программа будет ожидать нажатия клавиши, чтобы закрыть консольное окно. Вы получите дополнительное время, чтобы хорошенько всё рассмотреть/изучить. После нажатия любой клавиши, консольное окно закроется.

Другие решения, такие как system(«pause»); , могут работать только на определённых операционных системах, поэтому вариант выше предпочтительнее.

Примечание: Visual Studio не задерживает консольное окно, если выполнение запущено с отладкой («Отладка» > «Начать отладку» или F5). Если вы хотите, чтобы была пауза — воспользуйтесь решением выше или запустите программу без отладки («Отладка» > «Запуск без отладки» или Ctrl+F5).

Проблема №3

При компиляции программы я получаю следующую ошибку:
«c:vcprojectstest.cpp(263) :fatal error C1010: unexpected end of file while looking for precompiled header directive».

Ответ №3

Эта ошибка свидетельствует о том, что вы забыли подключить предварительно скомпилированный заголовок pch.h. Для устранения этой проблемы, вам нужно просто добавить следующую строчку кода в самый верх программы:

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

Проблема №4

При использовании cin, cout или endl компилятор говорит, что cin, cout или endl являются «undeclared identifier» (необъявленными идентификаторами).

Ответ №4

Во-первых, убедитесь, что у вас присутствует следующая строчка кода в верхней части вашей программы:

Во-вторых, убедитесь, что cin, cout или endl имеют префикс “std::”. Например:

Проблема №5

При использовании endl для перехода на новую строку, появляется ошибка, что end1 является «undeclared identifier».

Ответ №5

Убедитесь, что вы не спутали букву l (нижний регистр L) в endl с цифрой 1. В endl все символы являются буквами. Также легко можно спутать заглавную букву О с цифрой 0 (нуль).

Проблема №6

Моя программа компилируется, но работает не так как нужно. Что мне делать?

Ответ №6

Проблема №7

Как включить нумерацию строк в Visual Studio?

Ответ №7

Перейдите в меню «Средства» > «Параметры»:

Затем откройте вкладку «Текстовый редактор» > «Все языки» > «Общие» и поставьте галочку возле «Номера строк», затем нажмите «ОК»:

Проблема №8

При компиляции программы я получаю следующую ошибку: «unresolved external symbol _main or _WinMain@16».

Ответ №8

Это означает, что ваш компилятор не может найти главную функцию main(). Все программы должны содержать эту функцию.

Здесь есть несколько пунктов, которые нужно проверить:

Есть ли в вашей программе функция main()?

Слово main написано правильно?

Подключен ли файл, который содержит функцию main(), к вашему проекту? (если нет, то переместите функцию main() в файл, который является частью вашего проекта, либо добавьте этот файл в ваш проект)

Подключен ли файл, содержащий функцию main(), к компиляции?

Проблема №9

При компиляции программы я получаю следующее предупреждение: “Cannot find or open the PDB file”.

Ответ №9

Это не ошибка, а предупреждение. На работоспособность вашей программы оно не повлияет. Тем не менее, в Visual Studio вы можете решить всё следующим образом: перейдите в меню «Отладка» > «Параметры» > «Отладка» > «Символы» и поставьте галочку возле «Серверы символов (Майкрософт)», затем нажмите «ОК».

Проблема №10

Я использую Code::Blocks или G++, но функционал C++11/C++14 не работает.

Ответ №10

В Code::Blocks перейдите в «Project» > «Build options» > «Compiler settings» > «Compiler flags» и поставьте галочку возле пункта «Have g++ follow C++14 ISO C++ language standard». Смотрите урок № 4 — там есть скриншоты, как это сделать.

При компиляции в g++, добавьте следующий код в командную строку:

Проблема №11

Я запустил программу, появилось консольное окно, но ничего не выводится.

Ответ №11

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

У меня есть другая проблема, с которой я не могу разобраться. Как и где я могу получить ответ?

По мере прохождения уроков, у вас, несомненно, появятся вопросы или вы столкнетесь с проблемами. Что делать?

Во-первых, спросите у Google. Четко сформулируйте вашу проблему и просто погуглите. Если у вас есть сообщение об ошибке — скопируйте его и вставьте в поиск Google, используя кавычки. Скорее всего, кто-то уже задал такой же вопрос, как у вас, и получил на него ответ.

Если Google не помог, то спросите на специализированных сервисах вопросов/ответов/форумов. Вот самые популярные из них:

Но будьте внимательны и старайтесь максимально конкретизировать свою проблему, а также не забудьте указать, какую операционную систему и IDE вы используете, а также укажите, что вы пробовали сделать самостоятельно.

Тема: Помогите исправить ошибку в программе

Опции темы
  • Опции темы
  • Версия для печати
  • Отправить по электронной почте…

Необходимо расчитать многоступенчатый контроль для дипломной работы. Вот нашел лабораторную работу «Контроль партии изделий», контролируются резисторы. Расчёт идёт в QBasic.

Код программы:
CLS
REM «Vvod isxodnux dannux»
DATA 9.725, 10.2, .05, .01, 24, 3600
READ xo, xb, dx, em, nd, No
PRINT «xo=»; xo, «xb=»; xb, «dx=»; dx, «em=»; em, «nd=»; nd
DIM n(12)
DATA 0, 9, 32, 85, 153, 187, 155, 86, 33, 10, 0, 0
FOR i = 1 TO 12
READ n(i): PRINT n(i);
NEXT
PRINT
REM «bu4islenie srednego zna4enija k.p. i objema vuborki»
n = 0: xc = 0: x = xo
FOR i = 1 TO 12
n = n + n(i)
xc = xc + x * n(i)
x = x + dx
NEXT
xc = xc / n
PRINT «sr. zna4enie xc=»; xc, «ras4. objem vuborki n=»; n
REM «vu4islenie dispersii»
D = 0: x = xo
FOR i = 1 TO 12
D = D + n(i) * (x — xc) * (x — xc)
x = x + dx
NEXT
D = D / (n — 1): d1 = SQR(D)
PRINT «dispersija D=»; D, «sr. kvadr. otklonenie d=»; d1
REM «vu4islenie koefficienta soglasija»
m = 0: m1 = 0: x = xo
FOR i = 1 TO 12
t = (x — xc) / d1
f = EXP(-t * t / 2) / 2.5
p = dx * n * f / d1
m = m + p — n(i)
L = ABS(m)
IF L > m1 THEN m1 = L
x = x + dx
NEXT
L = m1 / SQR(n)
PRINT «koefficienta soglasija L=»; L
IF L No THEN PRINT : PRINT «partija otklonjaetsja po vxodn. ka4estvy»: END
REM «rezyljtayu tradicionnogo kontrolja»
p2 = em * fna(t) / (4 * d1)
n2 = 120000 * p2
PRINT «risk zakaz. P2=»; p2, «brak pri tr. kontrole Nm2=»; INT(Nm2)
IF n2

У меня при загрузке вашего текста выбило ошибку о второй копии одной и той же метки, плюс у вас отсутствовали переходы Goto перед вызовом метки. Я слегка подправил. Теперь протестируйте программу на правильность работы. Сам я не могу сказать что либо, ибо с электроникой знаком плохо, и слабо представляю для чего вообще служить программа.

Для того, чтобы на новых ОС видеть русский язык, нужно загрузить перед запуском самой программы какой нибудь русификатор, вроде keyrus.

Цукерберг рекомендует:  Изменение размера области сайта
Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих