Piros
Гость
|
|
« : 29-10-2004 18:29 » |
|
Необходимо было Составить программу анализа парности скобок, вводимых с клавиатуры. Использовать тип данных (класс) «стек». Моё Решение: #include <clx.h> #include<iostream.h> #include<conio.h> #pragma hdrstop #pragma argsused class stek {private: string q [10]; int sloc; public: void init(void); void qput(string x); string qget (void);}; void stek::init(void) {sloc = 0;} string stek:: qget(void) {if (sloc == 0) {cout<< "Skobok net"<<endl; return 0; // Подозреваю, что ошибка где-то тут }; cout<< "It is para"<< endl; return q[sloc--];}; void stek:: qput(string x) {if (sloc == 10) {cout<<" Stek polon"<<endl; return;} q [sloc++] =x;} int main(int argc, char* argv[]) { stek a; a.init(); int i; char x; string z; string y; string w; z="("; y=")"; for (i=0; i<9; i++){ cout<<"Vvedide skobky"<<endl; cin >> x; w=x; if (w==z) { a.qput(w);} else if (w==y) {a.qget();} else { cout<< x<<" Eto ne skobka"<<endl;} }; getch(); } Данная ошибка Project Project1.exe raised exception class EAccessViolation with message’Access violation at address 32657EBO. Read of address 00000000’. Process stopped. Use Step or Run to continue. возникает при попытке взять скобку из пустого стека.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #1 : 29-10-2004 18:57 » |
|
Вот программа приведенная в читаемый вид #include <clx.h> #include<iostream.h> #include<conio.h> #pragma hdrstop #pragma argsused
class stek { private: string q [10]; int sloc;
public: void init(void); void qput(string x); string qget (void); }; void stek::init(void) { sloc = 0; }
string stek:: qget(void) { if (sloc == 0) { cout<< "Skobok net"<<endl; return 0; // Подозреваю, что ошибка где-то тут }; cout<< "It is para"<< endl; return q[sloc--]; } ;
void stek:: qput(string x) { if (sloc == 10) { cout<<" Stek polon"<<endl; return; } q [sloc++] =x; }
int main(int argc, char* argv[]) { stek a; a.init(); int i; char x; string z; string y; string w; z="("; y=")"; for (i=0; i<9; i++) { cout<<"Vvedide skobky"<<endl; cin >> x; w=x; if (w==z) { a.qput(w); } else if (w==y) { a.qget(); } else { cout<< x<<" Eto ne skobka"<<endl; } } ; getch(); }
Первое что я увидел, у тебя не определен конструктор класса. init не является конструктором класса. Вот она и тебе и говорит, что класс не определен. т.е. его адрес размешения равен NULL. Да кстати, а что такое string?
|
|
« Последнее редактирование: 02-12-2007 16:49 от Алексей1153++ »
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #2 : 29-10-2004 18:58 » |
|
Взял твой код и прогнал в GCC (подправив под ISO) - ничего не валится. Работает, правда, криво, но работает.
Объясни, зачем в начале прагмы стоят, и что они делают? А также, что за хэдер clx.h и зачем он тут? Такое впечатление, что на C++ Builder написано...
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #3 : 29-10-2004 18:59 » |
|
Finch, объект класса не на указателе висит - выделение памяти пойдёт корректно, с вызовом конструктора по умолчанию.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #4 : 29-10-2004 19:04 » |
|
dimka, Я могу ее прогнать через Билдер. Сюдя по pragma это он. Первая #pragma hdrstop Это последуюшие хэдэры компилировать только по необходимости
Вторая #pragma argsused Если не указан аргумент, игнорировать ошибку
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #5 : 29-10-2004 19:53 » |
|
#include <clx.h> Мой компилятор отругался на эту строку. Пришлось убрать. return 0; // Подозреваю, что ошибка где-то тут Здесь надо записать так return "";Судя по всему компилятор считал, что ты возрашаеш символ с нулевого адреса. Что не допустимо. dimka, спасибо за науку. Будем знать.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Piros
Гость
|
|
« Ответ #6 : 30-10-2004 05:25 » |
|
писано сие действительно на борланд бьюлдере. Но уж извините на чём есть и что достал....
что значит работает но коряво? можно написать другой алгоритм, тогда подскажите....
я только учусь. но как я понял string это тип данных (нашёл оного в другой проге. и по варианту использования решил чо это так) если ошибаюсь - поправте!!!!
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #7 : 30-10-2004 11:20 » |
|
Finch, я и не заметил, что вместо строки число возвращается Ошибка именно там! Но GCC это переварил почему-то и не падал "Криво" означает, что я имею такой диалог с машиной: $ ./test Vvedide skobky (()) Vvedide skobky Vvedide skobky It is para Vvedide skobky It is para Vvedide skobky ) Skobok net Vvedide skobky (())) Vvedide skobky Vvedide skobky It is para Vvedide skobky It is para
По-моему: 1) не очевидно, что за один раз нужно вводить одну скобку, 2) "Введите скобку" повторяется к месту и не к месту, 3) нужно непременно 10 скобок. Но это работает
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #8 : 30-10-2004 12:20 » |
|
Piros, Если это реальная программа, а не учебная, то применять классы для такой задачи, это все равно, что дубинкой чинить часы. Вполне можно обойтись простым счетчиком. Проанализируй свою прогу. Ты практически не используеш свой стэк. Ты просто загоняеш туда открываюшую скобку "(" и все. Основная работа лежит на счетчике sloc. Конечно эпоха "скупого рыцаря" прошла. Но иногда нужно им быть. Тип string это наследник от паскаля. Обозначает просто строку с переменной длиной. Да в старой версии паскаля было ограничение до 255 символов. В этой строке string q [10]; ты просто объявляеш массив из строк. Логичнее использовать тип char т.е. просто символ.
|
|
« Последнее редактирование: 02-12-2007 16:50 от Алексей1153++ »
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Piros
Гость
|
|
« Ответ #9 : 01-11-2004 08:20 » |
|
это не реальная прога, это учебная... такое поставили задание. Сам вижу, что можно было и лучше, но уж что есть. всё заработало после замены return 0; на return ""; всем пасибо!!!! а может кто ещё объяснит более подробно почему именно так? и из-за чего ?
|
|
|
Записан
|
|
|
|
dedOK
Гость
|
|
« Ответ #10 : 01-11-2004 08:59 » |
|
А как на счет использования std::stack<char>? Тогда бы и ошибок не возникло.
|
|
|
Записан
|
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #11 : 01-11-2004 17:18 » |
|
а может кто ещё объяснит более подробно почему именно так? и из-за чего ? Тип string насколько я понял из описания хэлпа это ссылка на область памяти. Размер выделенной памяти меняется автоматически, в зависимости от длины строки. Когда ты написал return 0;. Ты как бы указал ссылку на строку начинаюшуюся с адреса 0. Что для программы не есть корректно. т.к. данные не могут лежать по адресу 0. Если бы ты написал return 8. То я думаю этот вариант прокатил бы на ура. Просто был бы возрат большого количества мусора. Так как ты не отслеживаеш возрат функций. Ты бы даже этого бы не заметил.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #12 : 01-11-2004 17:42 » |
|
Finch, опять не так Функция возвращает не указатель! В данном случае в при return в стеке создаётся объект типа string, который инициализируется пустой строкой. В случае return 0 в стеке создаётся объект типа int, инициализирующийся нулём. При возврате в вызывающую функцию размеры объектов не совпадают. В вызывающей функции происходит очистка стека, и она (вызывающая функция) пытается в стеке вычистить string, а на самом деле там int, который меньше string по размерам, в результате удаляется что-то лишнее, и всё валится. Я одного не пойму, зачем там вообще string возвращать? Возвращаемый результат нигде не используется. Там можно смело писать void и не мучаться . А ещё я не понимаю, почему компилятор не ругается на несовместимость типов
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #13 : 01-11-2004 17:53 » |
|
dimka, В тот день, я ради интереса просмотрел трассировку в ассемблере полученный код. Сначало происходило резервирование памяти под строку. Затем происходило копирование с 0 адреса в эту строку. Я дальше не стал разбираться, а что вообше возрашается с функции , но если хочеш, могу выложить полученный код. И вылет именно происходит в функции копирования. Это проверенно.
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
dedOK
Гость
|
|
« Ответ #14 : 01-11-2004 21:32 » |
|
Да кстати, а что такое string?...Тип string это наследник от паскаля. В C++ нет типа string и он никак не является наследником от паскаля. string - это синоним типа basic_string<char>, т. е. строка из символов типа char. basic_string - это шаблон класса, реализущего понятие строки. При return 0 вызывается следующий конструктор. Никакой несовместимости типов быть не может, т. к. в C++ легально преобразования целого 0 в нулевой указатель. basic_string (const charT * s, const Allocator& a = Allocator()); Этот конструктор создает строку, копируя содержимое начиная с указателя до нулевого символа. Если указатель некорректен (например, 0), то и возникает GP-ошибка. Если писать return "", к-р получит адрес массива из 1-го символа - нулевого. Т.е. пустую C-строку. И все корректно. Но более просто (и быстро) писать return string(). Функция возвращает не указатель! Действительно, функция возвращает - ВСЕГДА объект класса string. Сам класс хранит один указатель на область памяти, где хранится C-строка и счетчик ссылок на эту строку. В стеке CPU этот указатель от int ни чем не отличается. И вообще я не понял логики. Почему класс string из STL используется, а класс стек пишется свой? В STL имеется адаптор контейнера stack, реализующий понятие стека. include <stack> using namespace std; ... stack<string> a; // хотя лучше (как уже упоминалось) stack<char> a.push("("); // кинуть в стек string s; s = a.top(); // взять верхний a.pop(); // выкинуть из стека
Так разве не проще?
|
|
« Последнее редактирование: 02-12-2007 16:52 от Алексей1153++ »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #15 : 01-11-2004 21:48 » |
|
Finch тогда зависит от компилятора. По идее, 0 - это не адрес, а число. А память под string выделяется в стеке (не считая динамических структур самой string) Завтра спрошу, у нас люди как раз компилятор C++ пишут
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #16 : 02-11-2004 08:46 » |
|
люди знающие объяснили, что 0 - это особое число, которое автоматически преобразуется в NULL при надобности.
В таком случае валится он не при удалении объекта string из стека, а в конструкторе string.
т.е. return 0 воспринимается как return NULL, а это означает вызов конструктора string(char *), где NULL идёт в качестве указателя. C-шную строку в виде массива символов string пытается преобразовать во внутренее представление, т.е. пытается прочитать строчку, но так как она NULL, всё валится.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Finch
Спокойный
Администратор
Offline
Пол:
Пролетал мимо
|
|
« Ответ #17 : 02-11-2004 17:05 » |
|
dedOK, Спасибо за науку. Когда я имел в виду наследник. Я имел виду, что идеологию взяли с языка Паскаль. В стандартном С++, нет упоминания этого или по крайней мере я не видел. В паскале этот тип обозначал массив символов. В нулевой элемент массива записывалась длина строки. Когда была выпушена Дельфи. В Борланде чуть поменяли идеологию. Это так же массив символов. Но длина этого массива меняется динамически. Снято ограничение на 255 символов. Значение длины строки лежит не с нулевым смешением, а с смешением -4 .
|
|
|
Записан
|
Не будите спашяго дракона. Джаффар (Коша)
|
|
|
dedOK
Гость
|
|
« Ответ #18 : 15-11-2004 08:13 » |
|
Finch, насколько я помню, в Delphi 1 были обычные паскалевские строки в 255 символов. Пользователям это очень не нравилось. Поэтому в Delphi 2 добавили новый тип строки. Старый 255-символьный остался - ShortString, а новый - HugeString (или AnsiString - точно не помню). Оба типа присутствуют, а опциях настраивается что принимать за string - первый или второй.
Насчет идеологии, я бы не сказал, что взяли именно из ShortString и что именно из паскаля. Действительно, -4 хранится длина. Но еще -8 хранится счетчик ссылок на строку. Когда идет, например, присваивание, сама строка не копируется, а присваиваются указатели и увеличивается счетчик ссылок. Строка убивается - счетчик уменьшается. Если =0, то освобождается память. Такая идеология применяется широко и не только для строк.
|
|
|
Записан
|
|
|
|
|