Я расширю ответ Рупа, чтобы ответить на вопрос, который вы не задавали, но он важнее: Как узнать, где происходит сбой моей программы?
Один из способов - поместить в вашу программу операторы std::cout
или printf
. Поставьте оператор в начале каждой функции, говоря «function x enter», а в конце, говоря, «function x exit». Запустите вашу программу, и когда она выйдет из строя, вы увидите, в какой функции она находится. В этот момент вы можете добавить строки, чтобы напечатать содержимое каждой переменной, чтобы выяснить, что происходит не так.
Другой способ - использовать отладчик, например gdb
.
Сначала скомпилируйте вашу программу с ключом -g
, чтобы включить отладочную информацию.
linux@linux-ubuntu:~/t$ g++ prog.cpp -o prog -g
Затем скажите отладчику gdb
, чтобы он запустил вашу программу.
linux@linux-ubuntu:~/t$ gdb ./prog
В командной строке gdb введите run
, чтобы запустить вашу программу. Я ввел 4*(3+2)
и программа вылетела at prog.cpp:7
, то есть строка return Well.back();
.
(gdb) run
Starting program: /home/linux/t/prog
4*(3+2)
4
Program received signal SIGSEGV, Segmentation fault.
0x08048d0b in DishWell::ReturnEnd (this=0xbffff460) at prog.cpp:7
7 return Well.back();
Для более сложных программ вам часто требуется список всех функций, которые в данный момент вызываются. Вы можете получить эту информацию с помощью bt
, сокращение от "backtrace". В следующем следе вы видите, что функция main
(# 1) вызывает функцию DishWell::ReturnEnd
(# 0). # 0 - текущая функция, потому что функции формируют стек, где текущая функция является вершиной стека (смещение 0 является вершиной).
(gdb) bt
#0 0x08048d0b in DishWell::ReturnEnd (this=0xbffff460) at prog.cpp:7
#1 0x08048b35 in main (argc=1, argv=0xbffff534) at prog.cpp:75
(gdb)
Используя только эти 2 команды (run
, bt
), вы решили 80% проблемы: найти место, где произошла ошибка вашей программы. Если вы перестали читать здесь, вы сможете решить эту проблему, добавив операторы печати или утверждения, чтобы увидеть, каково состояние Well
и почему back()
приводит к сбою вашей программы. Но давайте использовать gdb
еще немного ...
Вы можете набрать list
, чтобы увидеть исходный код вокруг этой строки для большего контекста, не выходя из отладчика.
(gdb) list
2 using namespace std;
3
4 class DishWell{
5 public:
6 char ReturnEnd(){
7 return Well.back();
8 }
9 void Push(char x){
10 Well.push_back(x);
11 }
(gdb)
GDB может печатать переменные и простые выражения. Вывод значения Well
здесь не слишком полезен для новичка, потому что это сложная структура данных, а не простая переменная. Но мы можем сказать GDB вызвать метод для этой переменной ...
(gdb) print Well.size()
$2 = 0
(gdb) print Well.empty()
$3 = true
Ах, ха, Well
пусто, и вы назвали back()
на нем. Когда мы смотрим на хорошую документацию для std::vector
, мы видим, что вы вызываете неопределенное поведение, которое в данном случае является аварийным завершением программы.
Теперь просмотрите вашу программу и попытайтесь выяснить, почему Well
был пуст, когда ваша программа не ожидала, что он будет пустым. Если вам нравится gdb
, прочитайте некоторые учебники и узнайте, как делать такие вещи, как установка точек останова или один шаг.