Литмир - Электронная Библиотека
Содержание  
A
A

Увидеть, как вы добрались до этого места, можно с помощью команды

backtrace
:

(gdb)<b> backtrace</b>

#0 0x0804846f in sort (a=0x804a040, n=5) at debug3.c:23

#1 0x08048583 in main() at debug3.c:37

(gdb)

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

sort
была вызвана из
main
в строке 37 того же файла debug3.c. Обычно проблема гораздо сложнее, и команда
backtrace
применяется для определения маршрута, который привел к месту ошибки. Эта информация очень полезна при отладке функций, вызываемых из множества разных мест.

У команды

backtrace
есть сокращенная форма
bt
и для совместимости с другими отладчиками есть команда
where
, выполняющая ту же функцию.

Просмотр переменных

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

Функция

sort
была вызвана с параметром
а
, значение которого 0х804а040. Это адрес массива. Обычно он в различных системах разный и зависит от используемых компилятора и операционной системы.

Сбойная строка 23 — сравнение одного элемента массива с другим:

/* 23 */ if (a[j].key &gt; a[j+1].key) {

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

print
отображает содержимое переменных и других выражений:

(gdb) <b>print j</b>

$1 = 4

Вы видите, что у локальной переменной

j
значение
4
. Любые значения, выводимые командами gdb, подобными данной, сохраняются для будущего использования в псевдопеременных. В данном случае переменной
$1
присвоено значение 4, на случай, если она вам позже понадобится. Последующие команды будут сохранять свои результаты в переменных
$2
,
$3
и т.д.

Значение переменной

j
, равное 4, означает, что программа попыталась выполнить оператор

if (а[4].key &gt; а[4+1].key)

У массива

array
, который вы передали функции
sort
, только пять элементов, которые пронумерованы от 0 до 4. Поэтому данный оператор считывает несуществующий элемент массива
array[5]
. Переменная цикла
j
приняла некорректное значение.

Если ваша программа завершилась в строке 25, система обнаружила чтение за пределами массива, только когда взялась за перестановку элементов массива, выполнив оператор

/* 25 */ а[j] = a[j+1];

который при

j
, равной 4, дает в результате

а[4] = а[4+1];

Просмотреть элементы передаваемого массива можно, применив выражение в команде

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

(gdb) <b>print а[3]</b>

$2 = {data = &quot;alex&quot;, '\0' &lt;repeats 4091 times&gt;, key = 1}

(gdb)

Отладчик gdb сохраняет результаты выполнения команд в псевдопеременных вида

$&lt;<i>номер</i>&gt;
. Результат последней команды всегда хранится в псевдопеременной
$
, а предыдущей — в
$$
. Это позволяет результат одной команды использовать в другой. Например:

(gdb) <b>print j</b>

$3 = 4

(gdb) <b>print a[$-1].key</b>

$4 = 1

Вывод листинга программы

Вы можете в программе gdb вывести на экран исходный текст программы с помощью команды

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

(gdb) <b>list</b>

18 /* 18 */  int s = 1;

19 /* 19 */

20 /* 20 */  for(; i &lt; n &amp;&amp; s != 0; i++) {

21 /* 21 */   s = 0;

22 /* 22 */   for(j = 0; j &lt; n; j++) {

23 /* 23 */    if(a[j].key &gt; a[j+1].key) {

24 /* 24 */    item t = a[j];

25 /* 25 */    a[j] = a[j+1];

26 /* 26 */    a[j+1] = t;

27 /* 27 */    s++;

(gdb)

В строке 22 задано выполнение цикла до тех пор, пока переменная

j
меньше
n
. В данном случае
n
равна 5, поэтому у
j
будет последнее значение 4, слишком большое. Значение 4 приводит к сравнению
а[4]
с
а[5]
и возможной их перестановке. Единственное решение этой конкретной проблемы — исправить условие завершения цикла на следующее:
j &lt; n-1
.

Давайте внесем это изменение, назовем новую программу debug4.c, откомпилируем ее и попробуем снова выполнить.

/* 22 */   for(j = 0; j &lt; n-1; j++) {

$ <b>cc -g -o debug4 debug4.с</b>

$ <b>./debug4</b>

array[0] = {john, 2}

array[1] = {alex, 1}

array[2] = {bill, 3}

array[3] = {neil, 4}

array[4] = {rick, 5}

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

189
{"b":"285844","o":1}