Ошибка "Stack overflow"
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.217.146] |
|
|
Ошибка "Stack overflow"
|
Сообщ.
#1
,
|
|
|
|
Что значит эта 202 ошибка "Stack overflow"?
Я никак не могу понять, написал процедуру и вставил в программу, отдельно это процедура как программа работает, но не хочет работать как процедура в другой программе. Выдает ошибку 202. Вчера что-то помучился она работала, седня опять не работает. Выкладываю саму процедуру. Её задача открывать уже существующий файл нетекстовой, а двоичный, считывать данные и их сортировать и снова записывать в этот же файл. Доичный файл типа сисок. Вот типы чтобы легче было разобраться в конструкции. {type RecBook = record name:string[20]; phone:string[10]; end; tipfile = file of RecBook;} Сама процедура: ![]() ![]() Procedure Sort (var bookfile:tipfile); var work:recbook; i,j:integer; tmps:string[20]; a,b:array[1..100] of string; begin Name_File; {еще одна процедура, я ее внизу написал} assign(bookfile, name); reset(bookfile); for i:=0 to filesize(bookfile)-1 do begin read(bookfile,work); a[i]:=work.vardas; b[i]:=work.phone; end; for i:=0 to filesize(bookfile)-2 do for j:=i+1 to filesize(bookfile)-1 do begin if a[i] > a[j] then begin tmps:=a[i]; a[i]:=a[j]; a[j]:=tmps; tmps:=b[i]; b[i]:=b[j]; b[j]:=tmps; end; end; close(bookfile); reset(bookfile); for i:=0 to filesize(bookfile)-1 do with work do begin vardas:=a[i]; phone:=b[i]; write(bookfile,work); end; close(bookfile); end; Процедура File_Name: ![]() ![]() Procedure Name_File; begin write('Vvedite imia faila dannih telefonnogo spravo4nika > '); readln(name); end; Зарание спасибо. |
|
Сообщ.
#2
,
|
|
|
|
#MadCat#,
как вызываешь Sort, покажи... А лучше - приаттачь всю программу ![]() Цитата #MadCat# @ Что значит эта 202 ошибка "Stack overflow"? Цитата Эта ошибка генерируется на входе в процедуру или функцию, скомпилированную в режиме {$S+} в случае, если нет достаточной области памяти для размещения локальных переменных подпрограммы... Так что если с вызовом все в порядке - придется играть с директивой {$M a, b, c} Конкретнее - с первым параметром, определяющим размер стека. Можно, конечно, просто отключить контроль переполнения стека через {$S-}, но это как раз крайне нежелательно делать... Добавлено Кстати, можно попробовать сделать так: ![]() ![]() Procedure Sort (var bookfile:tipfile); var ... a, b:array[1..100] of string[20]; { <--- 20 вместо 255 !!! } Тогда в стеке будет заниматься гораздо меньший объем, а тебе строка длиннее 20 символов и не нужна... |
|
Сообщ.
#3
,
|
|
|
|
Цитата volvo877 @ Добавлено Кстати, можно попробовать сделать так: ![]() ![]() Procedure Sort (var bookfile:tipfile); var ... a, b:array[1..100] of string[20]; { <--- 20 вместо 255 !!! } Тогда в стеке будет заниматься гораздо меньший объем, а тебе строка длиннее 20 символов и не нужна... Во, точно, ты прав. Все теперь работает, спасибо. Ну, почему все-таки происходило переполнение, я несовсем понял? |
|
Сообщ.
#4
,
|
|
|
|
Я так понимаю, что стеки здесь не используются. Остаётся вариант - бесконечная рекурсия в программе (процедура вызвывает саму себя беск. кол-во раз).
|
|
Сообщ.
#5
,
|
|
|
|
Цитата Romtek @ Это как "не используются" ? А где же локальные переменные хранятся?Я так понимаю, что стеки здесь не используются. #MadCat#, массивы ![]() ![]() a, b:array[1..100] of string; занимают в стеке 2 * 100 * 255 байт... Это больше 50Кб. Стек по умолчанию устанавливается в 16384 байта. Так что одно из двух: либо уменьшать размер локальных переменных (что и было сделано), либо увеличивать размер стека... |
|
Сообщ.
#6
,
|
|
|
|
Цитата Romtek @ Это первое, что мне пришло в голову, т.к. и никогда не использую стек и когда у меня такая ошибка, значит я случайно вызвал процедуру внутри самой себя... Romtek, все проще Добавлено Цитата volvo877 @ Это я знаю. Я имел в виду саму структуру данных типа стек. Это как "не используются" ? А где же локальные переменные хранятся? |
|
Сообщ.
#7
,
|
|
|
|
volvo877 тут что-то с выводом теперь нето.
У тебе паскаль имеется? Если да попробуй запустить этот код. Я тут выкладываю его без поиска, изменения записи, дополнения они работают. Попробуй создать файл внести туда имя и телефон, а потом отсортировать и просмотреть его, там какая-то белеберда с выводом первой и второй записи телефонов. ![]() ![]() Program Book; uses crt; Type RecBook = Record vardas: string[20]; phone: string[10]; End; tipfile = file Of RecBook; Var bookfile: tipfile; work: RecBook; vid: byte; End_Menu: boolean; name: string[12]; Procedure Name_File; Begin write('Введите имя файла данных телефонного справочника > '); readln(name); End; Procedure Sort (Var bookfile:tipfile); Var i,j: integer; tmps: string[20]; a,b: array[1..100] Of string[20]; Begin Name_File; assign(bookfile, name); reset(bookfile); For i:=0 To filesize(bookfile)-1 Do Begin read(bookfile,work); a[i] := work.vardas; b[i] := work.phone; End; For i:=0 To filesize(bookfile)-2 Do For j:=i+1 To filesize(bookfile)-1 Do Begin If a[i] > a[j] Then Begin tmps := a[i]; a[i] := a[j]; a[j] := tmps; tmps := b[i]; b[i] := b[j]; b[j] := tmps; End; End; close(bookfile); reset(bookfile); For i:=0 To filesize(bookfile)-1 Do With work Do Begin vardas := a[i]; phone := b[i]; write(bookfile,work); End; close(bookfile); End; Procedure Create_book_Phone; Var Ind,Count: integer; Begin Name_File; Assign(Bookfile,name); Rewrite(Bookfile); writeln('Создание записей файла ', name); write('Введите число записей в справочнике '); readln(count); For Ind:=1 To count Do Addrec; writeln('Создание файла данных телефонного справочника завершено'); writeln('Файл данных имеет ',Filesize(bookfile),' записи'); close(bookfile); End; Procedure Outputrec; Begin read(bookfile,work); With work Do Begin write('Запись No ', Filepos(bookfile),' : '); writeln('ФИО: ',vardas,' телефон: ',phone); End; End; Procedure OutputAllrec; Begin Name_file; Assign(bookfile,name); {$I-} Reset(bookfile); {$I+} If IOresult = 0 Then Begin seek(bookfile, 0); writeln('*** Вывод телефонного справочника из файла ',name,'***'); while not Eof(bookfile) Do Outputrec; End Else writeln('Файла с именем ',name,' на диске нет'); End; Begin Clrscr; End_menu := false; Repeat writeln('*** Телефонный справочник ***'); writeln(' Выберите вид работы: '); writeln(' 1 - создание нового файла'); writeln(' 2 - просмотр'); writeln(' 3 - изменение записи'); writeln(' 4 - дополнение'); writeln(' 5 - сортировка'); writeln(' 6 - поиск'); writeln(' 0 - exit'); write('Ваш выбор '); readln(vid); Case vid Of 1: Create_book_phone; 2: Outputallrec; 3: Updaterec; 4: Addrectoend; 5: sort(bookfile); 6: search_pavarde; 0: end_menu := true; End; writeln('для продолжения нажмите Enter'); readln; clrscr; Until end_menu; End. |
|
Сообщ.
#8
,
|
|
|
|
Файл не компилируется - неполная версия.
Что значит "белибрда" ? Добавлено Почему work описана как глобальная переменная, а ты вводишь её ещё как локальную в Sort ? |
|
Сообщ.
#9
,
|
|
|
|
#MadCat#,
я тебе и без компиляции скажу, где проблема: ![]() ![]() Procedure Sort (var bookfile:tipfile); var ... a,b:array[1..100] of string[20]; begin ... for i:=0 to filesize(bookfile)-1 do begin read(bookfile,work); a[i]:=work.vardas; { <--- Вот тут проблема } b[i]:=work.phone; end; Ты же обращаешься к нулевому элементу, а он не определен... Если уж на то пошло, то я бы делал немного иначе (использовал бы счетчик, и при сортировке не привязывался к размеру файла, не нужно это никому...) : ![]() ![]() var count: integer; ... count := 0; while not eof(bookfile) do begin read(bookfile,work); inc(count); a[count]:=work.vardas; b[count]:=work.phone; end; for i:=1 to pred(count) do for j:=i+1 to count do begin ... end; |
|
Сообщ.
#10
,
|
|
|
|
Цитата Romtek @ Файл не компилируется - неполная версия. Что значит "белибрда" ? Добавлено Почему work описана как глобальная переменная, а ты вводишь её ещё как локальную в Sort ? Белиберда - это я имел ввиду, что там пишет какие-то неясные символы. А кто мне мешает переменную Work использовать в процедуре? Ну и что, что она глобальная, она как вспомогательная идет и в разных процедурах принимает разные значения типа списка. Цитата Если уж на то пошло, то я бы делал немного иначе (использовал бы счетчик, и при сортировке не привязывался к размеру файла, не нужно это никому...) : Да этот способ куда лучше, теперь нормально, т.е. теперь я могу не задавать в масиве String[20]? Можно просто, как String и переполнений не будет? Добавлено А, нет ругается все все-таки надо задавать ограничение. |
|
Сообщ.
#11
,
|
|
|
|
Цитата #MadCat# @ Можно просто, как String и переполнений не будет? Не меняй на String... Опять получишь "Stack Overflow", у тебя же опять размер локальных переменных увеличится...А хочешь еще одно улучшение? Смотри: ![]() ![]() Procedure Sort (Var bookfile:tipfile); Var tmps: RecBook; arr: array[1..100] Of RecBook; Begin ... Count := 0; While not Eof(bookfile) Do Begin Inc(count); Read(bookFile, arr[count]); End; for i:=1 to pred(count) do for j:=i+1 to count do begin if arr[i].vardas > arr[j].vardas then begin tmps := arr[i]; arr[i] := arr[j]; arr[j] := tmps; end; reset(bookfile); For i:=1 To count do write(bookfile, arr[i]); ... |
|
Сообщ.
#12
,
|
|
|
|
Цитата #MadCat# Ты сначала закрываешь файл, потом снова открываешь. Зачем?![]() ![]() close(bookfile); reset(bookfile); For i:=0 To filesize(bookfile)-1 Do With work Do Begin vardas := a[i]; phone := b[i]; write(bookfile,work); End; close(bookfile); Можно просто установить указатель файла на нулевую запись (начало) с помошью Seek (bookfile, 0); Тогда ![]() ![]() close(bookfile); reset(bookfile); Добавлено Цитата #MadCat# @ Чтобы по ошибке не подумать, что она имеет то же значение, что и в глобальной переменной.А кто мне мешает переменную Work использовать в процедуре? Ну и что, что она глобальная, она как вспомогательная идет и в разных процедурах принимает разные значения типа списка. Кстати, значения полей записи не нужно менять, т.к. ТП7 допускает присвоение записи значения другой записи, т.е. ![]() ![]() temp := work1; work1 := work2; work2 := temp; |
|
Сообщ.
#13
,
|
|
|
|
Цитата volvo877 @ Цитата #MadCat# @ Можно просто, как String и переполнений не будет? Не меняй на String... Опять получишь "Stack Overflow", у тебя же опять размер локальных переменных увеличится...А хочешь еще одно улучшение? Смотри: ![]() ![]() Procedure Sort (Var bookfile:tipfile); Var tmps: RecBook; arr: array[1..100] Of RecBook; Begin ... Count := 0; While not Eof(bookfile) Do Begin Inc(count); Read(bookFile, arr[count]); End; for i:=1 to pred(count) do for j:=i+1 to count do begin if arr[i].vardas > arr[j].vardas then begin tmps := arr[i]; arr[i] := arr[j]; arr[j] := tmps; end; reset(bookfile); For i:=1 To count do write(bookfile, arr[i]); ... А понятно всё. Тоже вариант неплохой. Цитата Ты сначала закрываешь файл, потом снова открываешь. Зачем? Можно просто установить указатель файла на нулевую запись (начало) с помошью Seek (bookfile, 0); Точно.Попробую. |
|
Сообщ.
#14
,
|
|
|
|
Цитата volvo877 @ #MadCat#, массивы ![]() ![]() a, b:array[1..100] of string; занимают в стеке 2 * 100 * 255 байт... Это больше 50Кб. 2*100*255=51000 байт, а 51000/1024=49,8kb... < 50kb |
|
Сообщ.
#15
,
|
|
|
|
Смысл от этого не изменился. Это все равно больше значения по умолчанию.
|
|
Сообщ.
#16
,
|
|
|
|
Цитата #MadCat# @ 2*100*255=51000 байт, а 51000/1024=49,8kb... < 50kb Цитата volvo877 @ А по-моему ошибка не из-за этого.Смысл от этого не изменился. Это все равно больше значения по умолчанию. ![]() ![]() var a, b: array[1..100] of string; s: string; i: byte; begin s := ''; for i := 1 to 255 do s := s + chr(i); for i := 1 to 100 do a[i] := s; a := b; end. |
|
Сообщ.
#17
,
|
|
|
|
Цитата Romtek @ Почему тогда здесь такой ошибки не возникает? здесь a и b - глобальные переменные, следовательно размещаются они в сегменте данных, а не в стеке... А размер DS = 64К. Но попробуй сделать так: ![]() ![]() var a, b, c: array[1..100] of string; ... Что будет? Сегмент данных переполняется и ... "Too many variables" В случае же локальных переменных - переполняется стек. Кстати, попробуй в исходной программе добавить {$M 65520, 0, 0} и переполнения уже не будет. |
|
Сообщ.
#18
,
|
|
|
|
Я пробовал также и с локальными переменными в процедуре, и тоже не было проблем (только если не больше двух переменных).
В программе Ash только 2 переменные. |
|
Сообщ.
#19
,
|
|
|
|
Ты хочешь сказать, что вот это:
![]() ![]() procedure test; var a, b: array[1..100] of string; s: string; i: byte; begin s := ''; for i := 1 to 255 do s := s + chr(i); for i := 1 to 100 do a[i] := s; a := b; end; begin test; end. у тебя компилируется и отрабатывает без ошибок? В Турбо-Паскале? У меня при входе в процедуру - "Stack Overflow". Может в FPC это и сработает, но в TP - нет... Кстати, возможно дело в этом: зайди в "Options -> Memory Sizes" и посмотри установленный по умолчанию размер стека. Может ты его переустанавливал. У меня он равен 16384... |
|
Сообщ.
#20
,
|
|
|
|
Цитата volvo877 @ Ты хочешь сказать, что вот это: ![]() ![]() procedure test; var a, b: array[1..100] of string; s: string; i: byte; begin s := ''; for i := 1 to 255 do s := s + chr(i); for i := 1 to 100 do a[i] := s; a := b; end; begin test; end. у тебя компилируется и отрабатывает без ошибок? В Турбо-Паскале? В настройках ничего не менял, стоит 16384 |
|
Сообщ.
#21
,
|
|
|
|
"Options -> Compiler -> Stack Checking" включен? При выключенном и у меня работает, но ... Сам понимаешь, чем это может кончиться
|
|
Сообщ.
#22
,
|
|
|
|
Цитата volvo877 @ ...выключен."Options -> Compiler -> Stack Checking" включен? Цитата volvo877 @ Buffer Overflow? ам понимаешь, чем это может кончиться |
|
Сообщ.
#23
,
|
|
|
|
Цитата Romtek @ Buffer Overflow? ![]() А попробуй запустить вот эту (правильную) программу: ![]() ![]() {$m 60000, 0, 0} procedure test; var a, b: array[1..100] of string; s: string; i, count: byte; begin s := ''; for i := 1 to 255 do s := s + chr(i); for i := 1 to 100 do a[i] := s; for i := 1 to 100 do if a[1] <> a[i] then inc(count); writeln(count); a := b; end; begin test; end. и свою: ![]() ![]() procedure test; var a, b: array[1..100] of string; s: string; i, count: byte; begin s := ''; for i := 1 to 255 do s := s + chr(i); for i := 1 to 100 do a[i] := s; for i := 1 to 100 do if a[1] <> a[i] then inc(count); writeln(count); a := b; end; begin test; end. И посмотри на результаты Чувствуешь разницу? |
|
Сообщ.
#24
,
|
|
|
|
Без галочки:
0 - твоя (проблем нет) 0 - моя (проблем нет) С галочкой: 0 - твоя (проблем нет) Stack overflow error (понятное дело! Вопрос: "на что это может повлиять?") |
|
Сообщ.
#25
,
|
|
|
|
Я не о том, что есть или нет проблемы
Сколько она тебе печатает? У меня без директивы {$M} (и без галочки, естественно) печатает число 24, то есть 24 (!!!) несовпадения 1-го элемента с последующими, а с директивой {$M} несовпадений нет...А сколько по-твоему НЕсовпадений должно быть? |
|
Сообщ.
#26
,
|
|
|
|
Я же написал, печатает 0 (ноль) без галки в обеих программах. Проверял 5 раз: то есть никаких отклонений не было найдено.
Цитата volvo877 @ Наверно зависит от того, насколько переполнен стек...не хочу гадать. А сколько по-твоему НЕсовпадений должно быть? Добавлено Я считаю, что проверки компилятора нужны только на этапе отладки программы, а в релизе программист должен учесть все варианты. |