Консультация № 187138
28.01.2013, 22:17
148.51 руб.
28.01.2013, 22:19
0 11 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:прога в паскалее выдает ошибку:Error 202: Stack Overflow Error.
и указывает на эту строку:
begin
pickup:=p^;{присваиваем функции значение по адресу указателя вершины стека}
if pickup>0 then {если не достигли дна стека}
dec(p) {уменьшаем адрес на 1 байт}
end;

Обсуждение

давно
Профессор
230118
3054
28.01.2013, 22:52
общий
Stack Overflow Error возникает при вызове подпрограмм, приведите программу полностью.
давно
Посетитель
7438
7205
29.01.2013, 11:52
общий
29.01.2013, 14:44
Полагаю, у Вас две ошибки:
1) Одной из задач стека является обеспечение работы с подпрограммами и функциями. Для этого в стек заносится адрес возврата.
После выхода из подпрограммы/функции осуществляется извлечение и переход на сохраненный адрес;
Вы же, выполняя dec(p), нарушили адресацию в стеке. В результате вершина стека указывает куда-то в другое место...
И выход из функции приведет "в молоко"...
2) Указатель стека обязан быть кратным 2, такая его специфика. Уменьшая его на 1, Вы и получили при обращении к стеку (pickup:=p^) указанное сообщение . Это в добавок к первой ошибке...

Какая была задача-то?
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Старший Модератор
31795
6196
29.01.2013, 17:42
общий
Покажите весь код, без него трудно, что либо сказать.


Обычно это занижен размер выделеного стека при компиляции(по умолчанию 16к), решается увеличением его до нужных размеров, максимум 64к.
В коде:
{$M размер стека , размер кучи}
или через меню:
Option | Compiler | Memory Size
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
29.01.2013, 18:46
общий
В любом случае это все только догадки. Нужен полный код, что и как определено.
Неизвестный
29.01.2013, 18:58
общий
30.01.2013, 14:13
вот полный код программы:

[code h=200]program diskr_math5;

uses crt;

const max=20;
p:^byte = nil; {указатель на вершину стека}

var n:byte;
A:array[1..max,1..max]of byte; {матрица смежности}
m:array[1..max]of byte; {массив пометок}
c:char;


{вывод матрицы смежности}
procedure printm;
var i,j:byte;
s:char;

begin
writeln('Матрица смежности');
writeln;
write(' ');
for i:=1 to n do begin
s:=char(i+96);
write(s);
end;
writeln;
writeln;
for i:=1 to n do begin
s:=char(i+96);
write(s,' ');
for j:=1 to n do begin
if A[i,j]<>1 then A[i,j]:=0;
write(A[i,j])
end;
writeln
end
end;

{контроль ошибок ввода смежных вершин}
function control(ch1,ch2:char):boolean;
var chn:char;

begin
chn:=char(n+96);
control:=true;
if (ch1<'a')or(ch1>chn)or(ch1=ch2) then begin
control:=false;
write(' Ошибка ввода!');
delay(1000);
delline;
gotoxy(1,wherey)
end
end;

{добавление ребер графа}
procedure addedge;
var i,j:byte;
s1,s2:char;

begin
repeat
clrscr;
writeln('Добавление ребер неориентированного графа');
writeln;
printm;
writeln;
if n=1 then break;
repeat
write('Укажите вершину ');
s1:=readkey;
write(s1);
until control(s1,'0');
writeln;
repeat
write('Укажите смежную вершину ');
s2:=readkey;
write(s2);
until control(s2,s1);
writeln;
i:=byte(s1)-96;
j:=byte(s2)-96;
A[i,j]:=1;
A[j,i]:=1;
writeln('1 - Добавить следующее ребро');
writeln('Любая клавиша - Меню');
until readkey<>'1'
end;

{удаление ребер графа}
procedure delledge;
var i,j:byte;
s1,s2:char;

begin
repeat
clrscr;
writeln('Удаление ребер неориентированного графа');
writeln;
printm;
writeln;
if n=1 then break;
repeat
write('Укажите вершину ');
s1:=readkey;
write(s1);
until control(s1,'0');
writeln;
repeat
write('Укажите смежную вершину ');
s2:=readkey;
write(s2);
until control(s2,s1);
writeln;
i:=byte(s1)-96;
j:=byte(s2)-96;
A[i,j]:=0;
A[j,i]:=0;
writeln('1 - Удалить следующее ребро');
writeln('Любая клавиша - Меню');
until readkey<>'1'
end;

{проверяет наличие вершины в массиве меток, если ее нет, то помечает}
function marker(v:byte):boolean;

begin
if m[v]=1 then marker:=true
else begin
marker:=false;
m[v]:=1
end
end;

{добавление вершины в стек}
procedure add(v:byte);

begin
inc(p);{увеличиваем адрес в указателе на 1 байт}
p^:=v {записываем вершину по этому адресу}
end;

{извлечение вершины из стека}
function pickup:byte;

begin
pickup:=p^;{присваиваем функции значение по адресу указателя вершины стека}
if pickup>0 then {если не достигли дна стека}
dec(p) {уменьшаем адрес на 1 байт}
end;

{обход компоненты связности графа}
procedure bypass(v:byte);
var i,j:byte;
s:char;

begin
new(p);
p^:=0; {устанавливаем указатель на 0}
add(v);{добавляем вершину в очередь}
marker(v);{отмечаем}
repeat
i:=pickup; {извлекаем вершину из очереди}
if i=0 then break; {если достигли дна стека, выходим из цикла}
s:=char(i+ 96);
write(s,' ');{печатаем ее}
for j:=1 to n do {проверяем строку этой вершины в матрице смежности}
if A[i,j]=1 then {если элемент в строке равен 1}
if marker(j)=false then
{проверяем вершину, соответствую этому cтолбцу на наличие в матрице меток,
если он отсутствует, то функция его автоматически добавляет}
add(j){добавляем его в очередь}
until false;
dispose(p)
end;

{поиск компонент связности графа}
procedure search;
var i,j:byte;

begin
for i:=1 to n do {заполнение массива меток нулями}
m[i]:=0;
clrscr;
printm;
writeln;
writeln('Компоненты связности неориентированного графа');
writeln;
j:=1;
for i:=1 to n do {пока в массиве меток есть неотмеченные вершины}
if m[i]=0 then begin
if wherey>24 then begin
write('Для продолжения нажмите любую клавишу');
readkey;
clrscr;
end;
write(j,': { ');
bypass(i); {выполняем обход начиная с этой вершины}
writeln('}');
inc(j)
end;
writeln;
writeln('Поиск завершен');
write('Для возвращения в меню нажмите любую клавишу ');
readkey
end;

begin
repeat
clrscr;
gotoxy(15,1);
writeln('МЕНЮ');
writeln;
writeln('1 - Задать порядок графа');
writeln('2 - Добавить ребра');
writeln('3 - Удалить ребра');
writeln('4 - Поиск компонент связности');
writeln('5 - Выход');

c:=readkey;
case c of
'1':repeat
clrscr;
writeln('Введите порядок графа от 1 до ',max);
writeln;
write('|V| = ');
readln(n)
until (n>0)and(n<max);
'2':addedge;
'3':delledge;
'4':search;
'5':break
end;
until false
end.[/code]
Неизвестный
29.01.2013, 19:10
общий
Ну вот, первое и заметное заметное - указатель = 4 байта, а Вы присваивайте его одному. Следовательно, все остальное теряется
function pickup:byte;

begin
pickup:=p^;{присваиваем функции значение по адресу указателя вершины стека}
if pickup>0 then {если не достигли дна стека}
dec(p) {уменьшаем адрес на 1 байт}
end;

Остальное тоже надо посмотреть
давно
Старший Модератор
31795
6196
29.01.2013, 19:47
общий
29.01.2013, 19:47
{извлечение вершины из стека}
function pickup:byte;

begin
pickup:=p^;{присваиваем функции значение по адресу указателя вершины стека}
if pickup>0 then {если не достигли дна стека}
dec(p) {уменьшаем адрес на 1 байт}
end;


Тут у Вас такая РЕКУРСИЯ "без права на посадку".
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
7438
7205
29.01.2013, 20:00
общий
29.01.2013, 20:10
Данная функция ошибочна
Код:
function pickup:byte;
begin
pickup:=p^;{присваиваем функции значение по адресу указателя вершины стека}
if pickup>0 then {если не достигли дна стека}
dec(p) {уменьшаем адрес на 1 байт}
end;

Написав if pickup>0 then вызывается бесконечная рекурсия (вызов самой себя), которая неминуемо приводит к вылету системного стека.
Может, стоит написать: if p^>0 then ?

Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
29.01.2013, 22:19
общий
это ответ
Здравствуйте, Посетитель - 368843!
Да, надо признать, что стоимость ответа явно завышена
Ошибка элементарная и никакое увеличение стека ее не поправит. Смотрите, что происходит:
1) Вы вызываете функцию pickup, в стек заносится адрес возврата (адрес следующей вызываемой команды, 2 байта);
2) потом, следующей командой, в регистр процессора (здесь AL) записывается значение переменной, на которую указывает указатель p;
3)
if pickup ...
- ЭТО ТОЖЕ ВЫЗОВ ФУНКЦИИ, т.е. переход к п.(1). И все .... Дальше НИЧЕГО не выполняется! Только вызывается, заносится, вызывается, заносится, вызывается ....
Т.е. нужно организовать локальную переменную и в нее записывать значение переменной. Во FreePascal, как в нормальном языке программирования, всегда в функции есть "встроенная" переменная Result, указатель на "тот" самый регистр процессора, с которой можно работать как с обычной переменной.
Посмотрите сами на результат своей работы. Если не будет получаться задуманное, напишите тут же, ответим за ту же самую сумму
--
Сейчас сил нет разбирать код -> я перешел на работу на завод и текущая деятельность заедает к вечеру
Неизвестный
29.01.2013, 22:30
общий
Уточню свой ответ, главным образом для въедливых коллег, п.(1) чуть по-иному выглядит: Сначала в стек записывается адрес возврата, и лишь потом функция вызывается
Неизвестный
30.01.2013, 18:53
общий
всем огромное спасибо, разобрался, всё работает
Форма ответа