[содержание] [назад] [пред] [вверх] [след] [вперед] 1. пример сеанса dddвы можете читать это руководство на досуге, чтобы узнать все о ddd. однако, чтобы приступить к использованию отладчика, достаточно знать лишь несколько возможностей. они описаны в данной главе.
программа-пример `sample.c' (см. раздел 1.1 пример программы) обнаруживает
следующую ошибку. программа $ ./sample 8 7 5 4 1 3 1 3 4 5 7 8 однако, при некоторых значениях аргументов она ошибается: $ ./sample 8000 7000 5000 1000 4000 1000 1913 4000 5000 7000
хотя вывод отсортирован и содержит верное число аргументов, некоторые
аргументы пропущены и заменены на странные числа; в данном случае
пропущено
давайте применим ddd, чтобы увидеть, что происходит. сначала вы
должны скомпилировать `sample.c' для отладки (см. раздел 4.1 компиляция для отладки), задав при компиляции флаг $ gcc -g -o sample sample.c
теперь вы можете вызвать ddd (см. раздел 2.1 вызов ddd) для исполняемого файла
$ ddd sample через несколько секунд появляется ddd. окно с исходным текстом содержит код отлаживаемой программы; для прокрутки по файлу используйте полоску прокрутки.
консоль отладчика (в самом низу) содержит информацию о версии ddd, а также подсказку gdb.(4) gnu ddd version 3.2.1, by dorothea l@"utkehaus and andreas zeller. copyright (c) 1999 technische universit@"at braunschweig, germany. copyright (c) 1999 universit@"at passau, germany. reading symbols from sample...done. (gdb)
первое, что нужно сейчас сделать -- установить точку останова
(см. раздел 5.1 точки останова), что заставит следующее, что нужно сделать, -- действительно запустить программу, чтобы вы могли исследовать ее поведение (см. раздел 6. запуск программы). для запуска программы выберите `program => run'; появится диалоговое окно `run program'.
теперь вы можете ввести в поле `run with arguments' аргументы
программы
теперь gdb запускает (gdb) break sample.c:31 breakpoint 1 at 0x8048666: file sample.c, line 31. (gdb) run 8000 7000 5000 1000 4000 starting program: sample 8000 7000 5000 1000 4000 breakpoint 1, main (argc=6, argv=0xbffff918) at sample.c:31 (gdb) выполняемая в текущий момент строка обозначена зеленой стрелкой. => a = (int *)malloc((argc - 1) * sizeof(int));
сейчас вы можете проверить значения переменных. чтобы проверить простую
переменную, вы можете просто поместить указатель мыши над ее именем и
задержать его там. спустя секунду всплывет маленькое окно со значением
этой переменной (см. раздел 7.1 просмотр простых значений с помощью подсказок). попробуйте проделать
это с `argv', чтобы увидеть ее значение ( чтобы выполнить текущую строку, щелкните на кнопке `next' из командной панели. стрелка продвинется на следующую строку. теперь снова укажите на `a' и увидите, что значение изменилось, и переменная `a' действительно стала инициализированной.
чтобы исследовать отдельные значения массива `a', введите в поле аргумента `a[0]' (вы можете заранее очистить его, щелкнув на `():'), а затем щелкните на кнопку `print'. это напечатает текущее значение `()' в консоли отладчика (см. раздел 7.2 печать простых значений в консоли отладчика). в нашем случае вы получите (gdb) print a[0] $1 = 0 (gdb) или какое-то другое значение (заметьте, что `a' была только размещена, но ее содержимое еще не проинициализировано.)
чтобы увидеть все члены `a' одновременно, вы должны применить
особый оператор gdb. поскольку `a' была размещена динамически,
gdb не знает ее размера; вы должны явно указать его, используя
оператор `@' (см. раздел 7.3.2.1 фрагменты массива). введите в поле
аргумента `a[0]@(argc - 1)' и щелкните кнопку `print'. вы
получите первые (gdb) print a[0]@(argc - 1) $2 = {0, 0, 0, 0, 0} (gdb) вместо того чтобы использовать `print' для просмотра текущего значения `a' на каждом останове, вы можете также отобразить `a', то есть сделать так, чтобы ее значение показывалось автоматически. щелкните на `display' оставив в поле аргумента `a[0]@(argc - 1)'. содержимое `a' теперь показывается в другом окне, окне данных. для горизонтального поворота массива щелкните на `rotate'.
далее идет присваивание значений членам `a': => for (i = 0; i < argc - 1; i++) a[i] = atoi(argv[i + 1]); теперь вы можете щелкать на `next' и снова на `next', чтобы увидеть, как происходит присваивание отдельным членам `a'. измененные члены подсвечиваются. для продолжения выполнения цикла используйте кнопку `until'. она велит gdb выполнять программу до тех пор, пока не будет достигнута строка, большая текущей. щелкайте на `until', пока не окажетесь на вызове `shell_sort': => shell_sort(a, argc); в этом месте содержимое `a' должно быть равно `8000 7000 5000 1000 4000'. снова щелкните на `next', чтобы пройти через вызов `shell_sort'. ddd остановится на цикле => for (i = 0; i < argc - 1; i++) printf("%d ", a[i]); и вы увидите, что после окончания `shell_sort' содержимое `a' стало равным `1000, 1913, 4000, 5000, 7000' -- то есть `shell_sort' каким-то образом испортил его. чтобы выяснить, что же случилось, выполните программу снова. на этот раз не проходите инициализацию, а перескочите прямо на вызов `shell_sort'. удалите старую точку останова, выбрав ее и щелкнув на `clear'. затем создайте новую точку останова в строке 35, перед вызовом `shell_sort'. для повторного выполнения программы выберите `program => run again'. опять же, ddd остановится перед вызовом `shell_sort': => shell_sort(a, argc); на этот раз вы хотите ближе исследовать, что делает `shell_sort'. щелкните на `step', чтобы войти в вызов `shell_sort'. это оставит вашу программу на первой исполняемой строке, => int h = 1; тогда как консоль отладчика говорит нам, что произошел вход в функцию: (gdb) step shell_sort (a=0x8049878, size=6) at sample.c:9 (gdb) такой вывод, показывающий функцию (и ее аргументы), где остановлено выполнение `sample', называется отображением стека фреймов. он дает представление о содержимом стека. вы можете использовать `status => backtrace', чтобы узнать, в каком месте стека вы находитесь; если выбрать строку (или щелкнуть на `up' или `down'), вы сможете перемещаться по стеку. обратите внимание на то, что отображение `a' исчезает, когда вы покидаете его фрейм.
давайте теперь проверим правильность аргументов `shell_sort'. вернувшись в самый нижний фрейм, введите в поле аргумента `a[0]@size' и щелкните на `print': (gdb) print a[0] @ size $4 = {8000, 7000, 5000, 1000, 4000, 1913} (gdb)
сюрприз! откуда взялось это лишнее значение чтобы понять, действительно ли это является причиной ошибки, вы можете теперь присвоить `size' правильное значение (см. раздел 7.3.3 присваивание переменных). выберите в исходном коде `size' и щелкните на `set'. появится диалоговое окно, где вы можете отредактировать значение этой переменной.
измените значение `size' на (gdb) set variable size = 5 (gdb) finish run till exit from #0 shell_sort (a=0x8049878, size=5) at sample.c:9 0x80486ed in main (argc=6, argv=0xbffff918) at sample.c:35 (gdb) получилось! для `a' теперь показаны корректные значения `1000, 4000, 5000, 7000, 8000'.
вы можете убедиться, что эти значения будут на самом деле напечатаны на стандартный вывод, выполнив программу дальше. щелкните на `cont', чтобы продолжить выполнение. (gdb) cont 1000 4000 5000 7000 8000 program exited normally. (gdb)
сообщение `program exited normally.' исходит от gdb; оно
говорит, что программа найдя причину ошибки, вы теперь можете исправить исходный код. щелкните на `edit', чтобы отредактировать `sample.c', и измените строку shell_sort(a, argc); на корректный вызов shell_sort(a, argc - 1);
теперь вы можете перекомпилировать $ gcc -g -o sample sample.c
и проверить (через `program => run again'), что
(gdb) run `sample' has changed; re-reading symbols. reading in symbols...done. starting program: sample 8000 7000 5000 1000 4000 1000 4000 5000 7000 8000 program exited normally. (gdb) все готово; сейчас программа работает правильно. вы можете завершить этот сеанс ddd с помощью `program => exit' или ctrl+q. 1.1 пример программыэто исходный файл `sample.c' программы-примера.
/* sample.c -- sample c program to be debugged with ddd */ #include <stdio.h> #include <stdlib.h> static void shell_sort(int a[], int size) { int i, j; int h = 1; do { h = h * 3 + 1; } while (h <= size); do { h /= 3; for (i = h; i < size; i++) { int v = a[i]; for (j = i; j >= h && a[j - h] > v; j -= h) a[j] = a[j - h]; if (i != j) a[j] = v; } } while (h != 1); } int main(int argc, char *argv[]) { int *a; int i; a = (int *)malloc((argc - 1) * sizeof(int)); for (i = 0; i < argc - 1; i++) a[i] = atoi(argv[i + 1]); shell_sort(a, argc); for (i = 0; i < argc - 1; i++) printf("%d ", a[i]); printf("\n"); free(a); return 0; } [содержание] [назад] [пред] [вверх] [след] [вперед] |