Будьте добры,уважаемые форумчане можете исправить ошибку в данном коде программе.Уж очень срочно надо.Буду очень признателен.А вот и само условие и код программы: Исходные данные находятся в текстовом файле. Разделитель – конец строки. Программа запрашивает имя входного и результирующего (отсортиро-ванного) файла. Использовать динамическое распределение памяти.И надо сортировать строки методом пузырька.Тут как бы всё правилььно выполняет,только вот пишет ошибку .. и как мне подсказывали что-то с указателями.Или после кода программы"void main(void)..."
P.S.Прошу прощение,за повтор темы.Хотел удалить ,но не нашёл.
volvo
8.05.2008 3:57
Можно уточнить? зачем понадобилось перемешивать чистый С и C++ (ну, например, работать в одной программе и с FILE* и с потоками) ? Если у тебя С++, то работай с ifstream/ofstream, это ж проще гораздо...
К тому же С++ не позволяет делать void main(), функция main должна возвращать результат типа int...
А вот это:
char *nam = new char[];
вообще недопустимо: ты не указываешь размер выделяемой области памяти, ни один компилятор этого не пропустит...
А вот задание уточни: каков критерий сортировки? Строки можно сортировать по алфавиту, можно - по количеству слов, можно - по числу знаков препинания, да мало ли еще как...
V.k.l.chr.by
8.05.2008 4:08
Вообщем я просто брал нечто похожую программу с лабораторной работы и вставлял и вышел такой просяк.Да и где-то помогали мне.Так что решил когда заработает программа,тогда и каждую строчку попробую разобраться.А сортироватьться строки будут по буквам как в словари.Тоетсь первая буква перовй строки с второй строки первой буквы.
volvo
8.05.2008 5:27
Цитата
Так что решил когда заработает программа,тогда и каждую строчку попробую разобраться
Неправильно... Разбираться надо, ЧТОБЫ программа заработала...
Попробуй разобраться:
#include <windows.h>
#include <iostream> #include <fstream>
using namespace std;
void write_lines(ostream& os, char* ptr[], int n_lines) { for(int i = 0; i < n_lines; i++) { char *str = strdup(ptr[i]); CharToOem(str, str); os << str << endl; free(str); } }
char buffer[buf_size]; int current = -1; while(in.getline(buffer, buf_size)) { ptr[++current] = new char[strlen(buffer) + 1]; strcpy(ptr[current], buffer); }
cout << s_before << endl; write_lines(cout, ptr, current + 1); sort(ptr, current + 1); cout << s_after << endl; write_lines(cout, ptr, current + 1);
write_lines(out, ptr, current + 1); for(int i = 0; i <= current; i++) { delete ptr[i]; }
return 0;
}
В принципе, тут можно было обойтись вообще десятком строк для сего, что делается в программе, но ты сам хотел char* и динамическое выделение памяти...
P.S. CharToOem может не сработать, поэтому я ее закомментировал. Попробуй...
V.k.l.chr.by
8.05.2008 5:30
Просто в условии дано ,чтобы было динамичесткое распределение памяти.Что ж кажись всё правильно.Только вот ,если русские символы в текстовом файле находяться,то в новом файле после сортирвоке появляются непонятные символы.Не мог ли бы исправить.А так ,если английские символы всё отлично.Большое ,спасибо!
V.k.l.chr.by
9.05.2008 16:46
Проверил ещё раз,всё ровно русские символы не сортируютсяв текстовом файле(непонятные ироглифы),а сама сортирвока в чёрнмом окошке всё нормально.Не помогли ли Вы помочь разобраться?Я так понимаю,чт окажись загвоздка в строке
Код
CharToOem(str, str);
Так как ,я взял и данную строку закомментировал и уже файл нормально отсортировался,но возникла проблемав черном окошке(непоняные ироглифы)
volvo
9.05.2008 19:08
Цитата
я взял и данную строку закомментировал и уже файл нормально отсортировался,но возникла проблемав черном окошке(непоняные ироглифы)
Ну, так возьми и чуть-чуть подкорректируй write_lines, чтобы CharToOem вызывалась только тогда, когда вывод происходит на экран:
void write_lines(ostream& os, char* ptr[], int n_lines) { for(int i = 0; i < n_lines; i++) { char *str = strdup(ptr[i]);
if(os == cout) { // <--- Вот эта строка CharToOem(str, str); }
os << str << endl; free(str); } }
V.k.l.chr.by
9.05.2008 22:26
Ух..выручили Вы меня всё тепреь работает!!Ура с победой!!Та кже небольшйо вопрос.. а можно задавать вопросы по задачке.Просто как моей помощи мало было.Поэтмоу ,чтобы защитить эту задачку за зачёте,хотелсоь разобрат ькаждую строчку.Так что если будут вопрсоы можно задавать?
volvo
9.05.2008 23:33
Цитата
Так что если будут вопрсоы можно задавать?
Задавай, конечно... Для этого форум и существует - чтобы помочь разобраться с тем, что непонятно...
V.k.l.chr.by
11.05.2008 3:40
И так мне уже в начале не понятно первые строчки.А именно:"void write_lines(ostream& os, char* ptr[], int n_lines) { for(int i = 0; i < n_lines; i++) { char *str = strdup(ptr[i]);" Если можно каждую строчку прокоментировать.Само слово void я так понял -это типо функция которая не будет возращат значение.В даном случае её название"write_lines"А дальше не понял.Но там я та кпонял что-то связано с указателями.Я не очень и так понял про указатели.Если вообщем,то они выделяют память под объект,если так,тогда когда пишем простые программы мы вообще не использовали память.Тогда вопрос,откуда появлялась память,в тех простых программах?
volvo
11.05.2008 4:04
// функция write_lines описывается как void - не возвращающая результата // принимает 3 параметра: // 1) ссылку на поток вывода, куда собственно будет производиться вывод // 2) массив указателей на строки // 3) число строк void write_lines(ostream& os, char* ptr[], int n_lines) {
// для всех номеров строк от 0 до n_lines - 1 (в С++ индексация всегда начинается с 0) for(int i = 0; i < n_lines; i++) {
// при помощи библиотечной функции strdup выделяется память, необходимая // для хранения i-той строки массива, и сама строка копируется в динамическую память // (фактически - создается копия строки) char *str = strdup(ptr[i]);
// если в функцию был передан поток cout (связанный с консолью), то ... if(os == cout) { // конвертируем копию строки в OEM, для правильного отображения CharToOem(str, str); }
// и выводим копию строки в поток (это может быть не только консоль, // но и любой поток вывода, скажем, файл)... os << str << endl;
// и освобождаем память, удаляя копию строки, она нам больше не понадобится free(str); } }
Цитата
Тогда вопрос,откуда появлялась память,в тех простых программах?
Ну, если программки были совсем простые, значит все переменные создавались статически, то есть вся необходимая память выделялась еще при компиляции...
V.k.l.chr.by
16.05.2008 2:03
Вообщем всё понятно,но возникли небольшие вопросики. 1-Почему,в коде программы нельзя было просто написать до N,а не n_lines? 2-И у Вас в комментарии написано,что "до n_lines - 1"Причём тут единица. 3-И если не трудно,можно ещё пару слов об "os"ЧТо это такое?Я как понял,это назваине потока,благодаря чему будет копироваться троки в файл.Я так понял?
-
// для всех номеров строк от 0 до n_lines - 1 (в С++ индексация всегда начинается с 0) for(int i = 0; i < n_lines; i++) {
Я так подумал вышлю остальной код программы(если не трудно прокментировать его),чтобы после сего,по частям разбарал бы и если что вопрсоызадавал бы.Думаю так быстрее будет,чем по частям высылать и так же уже нужно скоро уже относить программу. p/S/Я ещё раз хочу выразить благодарность за помощь студенту. -
char buffer[buf_size]; int current = -1; while(in.getline(buffer, buf_size)) { ptr[++current] = new char[strlen(buffer) + 1]; strcpy(ptr[current], buffer); }
cout << s_before << endl; write_lines(cout, ptr, current + 1); sort(ptr, current + 1); cout << s_after << endl; write_lines(cout, ptr, current + 1);
write_lines(out, ptr, current + 1); for(int i = 0; i <= current; i++) { delete ptr[i]; }
return 0;
}
volvo
16.05.2008 3:19
Цитата(V.k.l.chr.by @ 15.05.2008 22:03)
1-Почему,в коде программы нельзя было просто написать до N,а не n_lines?
Ну, если тебе удобнее до N, то пиши до N, я привык давать "говорящие" имена переменным...
Цитата(V.k.l.chr.by @ 15.05.2008 22:03)
в комментарии написано,что "до n_lines - 1"Причём тут единица.
При том, что если число строк это n_lines, то значит, их индексы - от 0 до (n_lines-1)
Цитата(V.k.l.chr.by @ 15.05.2008 22:03)
можно ещё пару слов об "os"ЧТо это такое?
Это поток вывода, os (сокращение от output stream)... Понимаешь в чем дело... Когда запускается программа на С++, создаются несколько потоков. Один (cout, стандартный вывод на экран) - для вывода данных, другой (cin, стандартный ввод с клавиатуры) - для ввода данных в программу. Ну, есть еще cerr/clog, но это пока не важно... Так вот, cout имеет тип ostream. От этого же типа унаследован и файловый поток (ofstream), то есть, в свою процедуру я могу передать (по правилу совместимости типов) не только сам cout, но и любого его наследника, и если я передам файловый поток, то все то, что должно было бы напечататься на экране, будет выведено в файл... Чем я и воспользовался... Когда мне нужно - вывожу данные на монитор, а когда нужно - в файл...
Теперь что касается остальной программы:
Это - самая обычная сортировка "пузырьком" массива ptr, содержащего n_lines строк. Алгоритм этот найдешь на любом сайте, да хоть у нас в FAQ-е по Паскалю: Методы сортировок
// место для имен входного/выходного файлов char in_name[64], out_name[64];
// максимальное число строк, которые будут обрабатываться. // Если в файле будет больше строк, чем указано здесь - то массив, // описанный чуть ниже, переполнится и получишь Access Violation - ошибку доступа const int maxLines = 1000;
// Вот, собственно, массив для хранения указателей на строки char *ptr[maxLines];
// запрашиваем у пользователя и вводим имя входного файла cout << s_in_name; cin >> in_name;
// открываем файловый поток in для чтения ifstream in(in_name, ios::in); if(!in) { // поток не открылся, выходим с ошибкой cout << s_err_open << endl; return -1; }
// запрашиваем и принимаем от пользователя имя выходного файла cout << s_out_name; cin >> out_name;
// опять же открываем файловый поток, но теперь уже на запись ofstream out(out_name, ios::out); if(!out) { // не открылся - ошибка cout << s_err_open << endl; return -1; } // максимальное количество символов, читаемое из файла за один раз const int buf_size = 1024; // ну, и буфер для временного хранения прочитанной из файла строки char buffer[buf_size];
// здесь будет номер строки, прочитанной из файла на каждой итерации цикла // для начала (-1), потом поймешь почему... int current = -1;
// попытка прочесть до buf_size символов (на самом деле может быть прочитано // и меньше, поскольку чтение завершится как только встретится символ "\n") // из файла in в buffer... // пока эти попытки успешны (т.е., строка читается) while(in.getline(buffer, buf_size)) { // увеличиваем номер текущей строки (теперь понятно, почему изначально был (-1)? // Потому что начинается индексация с 0), и для текущего номера выделяется память, // достаточная для хранения прочитанной из файла строки... ptr[++current] = new char[strlen(buffer) + 1];
// как только память выделена - копируем строку из временного буфера в дин. память strcpy(ptr[current], buffer); }
// Ну, а дальше - все просто: выводим все прочитанные строки в cout // (т.е., на монитор), как именно, я уже объяснял cout << s_before << endl; write_lines(cout, ptr, current + 1);
// сортируем массив строк (поскольку current содержит индекс последней // прочитанной строки начиная с 0, а в процедуру сортировки нужно передать // КОЛИЧЕСТВО строк, то передаем current + 1) sort(ptr, current + 1);
// и уже отсортированные строки выводим сначала на монитор (cout)... cout << s_after << endl; write_lines(cout, ptr, current + 1);
// ... а потом - в файловый поток, открытый нами для записи write_lines(out, ptr, current + 1);
// Все, строки сохранены, можно дин. память освобождать for(int i = 0; i <= current; i++) { delete ptr[i]; }
return 0;
}
По-моему несложно...
V.k.l.chr.by
16.05.2008 4:42
Спасибо.Но и в правду как бы всё понятно. Так же хочу вернуться к ...
Цитата
Ну, если программки были совсем простые, значит все переменные создавались статически, то есть вся необходимая память выделялась еще при компиляции...
Я как читил,что каждый тип имеет определённый диапозон.Получатеся,если в простых программах этот диапозон нам вполне хватал,то в случае больших программах как в моей,ей болльше потребуеться диапозон и поэтому и нужны указатели.Правильно ли я расcуждаю? Так же я хотел вашего совета,как всё таки начитсья правильно составлять алгоритмы для решение той или иной программы.Я к чему,к тому что как бы теория понятно,а вот напрактики чтобы это применить не очень получаеться.То ли у меня слабо мышление,или как бы первый курс и надо побольше решать задач,чтобы набратсья опыта.И меня так же заинтересовало,так где же этот тот же метод пузырбка применяеться,ну можетв програамах каких либо.Может частично он применяется в программе тот же "телефонный справочник"где он сортирует фамилии.И так если не трудно прокоментировать характеристики на данной ссылке http://forum.pascal.net.ru/index.php?act=Attach&type=post&id=986 Читал,что метод пузырька считается самый легкий способ,но и не очень часто он используется он.Может я благодаря этой характеристе и получу на свой ответ,почему он на столько плох.Думаю Вас не загрузил своим дурацкими вопросами.
volvo
16.05.2008 5:49
Дело не в диапазоне... Дело в том, что память в программе может выделяться при компиляции и во время работы. Вот, скажем пример программы, которой тоже вроде бы не нужно многое, но без указателей в ней обойтись нельзя (здесь я бы попросил более опытных программистов не напоминать про продвинутые библиотеки языка, я о них не забыл, помню, что можно и без указателей, но на _таком_ уровне лучше об этом не упоминать, иначе в голове останется только каша...): написать программу, которая получит от пользователя число, организует массив из этого количества элементов, и обрабатывает его... Все просто, правда? Но ты не можешь написать так:
// тут подключение заголовочных файлов int main() { int n; cin >> n;
int arr[n]; for(int i = 0; i < n; i++) { arr[i] := i; // для примера } ... // работаем с массивом return 0; }
, потому что память под массив выделяется при компиляции, а ты еще не знаешь, что введет пользователь... (вернее, это возможно, но только на определенном компиляторе. Сменишь компилятор - придется переписывать программу, поэтому данный способ лучше не использовать). Придется делать так:
// тут подключение заголовочных файлов int main() { int n; cin >> n;
int *arr = new int[n]; // выделяем в "куче" память под n элементов типа int for(int i = 0; i < n; i++) { arr[i] := i; // работаем точно так же, как и со статическим массивом } ... // работаем с массивом delete arr; // не забываем освободить память return 0; }
Вот тебе и необходимость (вернее одна из необходимостей) использования указателей... Я не буду углубляться в дебри, и не стану говорить ничего про массивы и указатели, про строки - тебе надо бы прочесть какую-нибудь книжку по С++, чтобы понять основы, потом можно будет разговаривать дальше...
Цитата
меня так же заинтересовало,так где же этот тот же метод пузырбка применяеться,ну можетв програамах каких либо
В принципе, он может применяться где угодно - это полноценный метод сортировки, только медленный очень, что и видно из сравнения времени выполнения сортировок разными алгоритмами: сортировка методом "пузырька" выполняется медленнее, чем любым другим методом при любых размерах массивов; чем размер больше, тем отрыв заметнее... Но у него есть и преимущество: он очень простой, и иногда (если надо быстро написать программку, сортирующую небольшой массив) очень даже может использоваться (потому как набирается просто автоматически)...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.