IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Ошибка в коде программы(С++), Сортировка строк методом пузырька
сообщение
Сообщение #1


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Будьте добры,уважаемые форумчане можете исправить ошибку в данном коде программе.Уж очень срочно надо.Буду очень признателен.А вот и само условие и код программы:
Исходные данные находятся в текстовом файле. Разделитель – конец строки. Программа запрашивает имя входного и результирующего (отсортиро-ванного) файла. Использовать динамическое распределение памяти.И надо сортировать строки методом пузырька.Тут как бы всё правилььно выполняет,только вот пишет ошибку .. и как мне подсказывали что-то с указателями.Или после кода программы"void main(void)..."


#include<stdio.h>
#include<windows.h>
#include<string.h>
#include<iostream.h>

#define maxline 1000

void sort(char* ptr[],int n_lines)
{
int i,j;
char *tmp;
for(i=0;i<n_lines-1;i++)

for(j=0;j<n_lines-1;j++)

if(strcmp(ptr[j],ptr[j+1])>0)
{
tmp=ptr[j];
ptr[j]=ptr[j+1];
ptr[j+1]=tmp;
}


}
void write_lines(char* ptr[],int n_lines)
{
int i;
char *str = new char[];
for(i=0;i<n_lines;i++)
{
CharToOem(ptr[i],str);
cout<<str<<endl;

}
}

void write_in_file(char* ptr[],int n_lines, FILE* fp)
{
int i;
char *str = new char[];
for(i=0;i<n_lines;i++)
{
fputs(ptr[i],fp);
fputs("\n",fp);


}
}

void main(void)
{

char s[] = "Введите путь к файлу : ";
CharToOem(s,s);
char r[] = "Введите путь к отсортированному файлу : ";
CharToOem(r,r);
char a[] = "Ошибка при открытии файла\n";
CharToOem(a,a);
char ns[] = "До сортировки :";
CharToOem(ns,ns);
char ps[] = "После сортировки :";
CharToOem(ps,ps);


FILE *in;
char *str = new char[];
char *name = new char[];
int counter=0;
char buf[maxline];
char *ptr[maxline];
cout<<s;
cin>>name;

if((in=fopen(name,"rt"))==NULL)
{
cout<<a;
return;
}

FILE *fp;
char *nam = new char[];
cout<<r;
cin>>nam;
fp=fopen(nam,"wt");

for(counter=0;(!feof(in))&&counter<maxline;counter++)
{
fgets(buf,maxline,in);
if(buf[strlen(buf)-1]=='\n')
{
buf[strlen(buf)-1]='\0';
}
ptr[counter] = new char[strlen(buf)+1];
strcpy(ptr[counter],buf);
buf[0]='\0';

}

fclose(in);
cout<<ns<<endl;
write_lines(ptr,counter);
cout<<endl<<endl<<ps<<endl;
sort(ptr,counter);
write_lines(ptr,counter);
write_in_file(ptr,counter,fp);
fclose(fp);

}
P.S.Прошу прощение,за повтор темы.Хотел удалить ,но не нашёл.

Сообщение отредактировано: volvo -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Можно уточнить? зачем понадобилось перемешивать чистый С и C++ (ну, например, работать в одной программе и с FILE* и с потоками) ? Если у тебя С++, то работай с ifstream/ofstream, это ж проще гораздо...

К тому же С++ не позволяет делать void main(), функция main должна возвращать результат типа int...

А вот это:
char *nam = new char[];

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

А вот задание уточни: каков критерий сортировки? Строки можно сортировать по алфавиту, можно - по количеству слов, можно - по числу знаков препинания, да мало ли еще как...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Вообщем я просто брал нечто похожую программу с лабораторной работы и вставлял и вышел такой просяк.Да и где-то помогали мне.Так что решил когда заработает программа,тогда и каждую строчку попробую разобраться.А сортироватьться строки будут по буквам как в словари.Тоетсь первая буква перовй строки с второй строки первой буквы.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






Цитата
Так что решил когда заработает программа,тогда и каждую строчку попробую разобраться
Неправильно... Разбираться надо, ЧТОБЫ программа заработала...

Попробуй разобраться:
#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);
}
}

void sort(char* ptr[], int n_lines) {
for(int i = 0; i < n_lines; i++) {
for(int j = n_lines - 1; j > i; j--) {
if(strcmp(ptr[j - 1], ptr[j]) > 0) {
char *tmp = ptr[j-1];
ptr[j-1] = ptr[j];
ptr[j] = tmp;
}
}
}
}


int main()
{

char s_in_name[] = "Введите путь к файлу : ";
// CharToOem(s_in_name, s_in_name);

char s_out_name[] = "Введите путь к отсортированному файлу : ";
// CharToOem(s_out_name, s_out_name);

char s_err_open[] = "Ошибка при открытии файла\n";
// CharToOem(s_err_open, s_err_open);

char s_before[] = "До сортировки :";
// CharToOem(s_before, s_before);

char s_after[] = "После сортировки :";
// CharToOem(s_after, s_after);

char in_name[64], out_name[64];

const int maxLines = 1000;
char *ptr[maxLines];


cout << s_in_name;
cin >> in_name;

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];
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 может не сработать, поэтому я ее закомментировал. Попробуй...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Просто в условии дано ,чтобы было динамичесткое распределение памяти.Что ж кажись всё правильно.Только вот ,если русские символы в текстовом файле находяться,то в новом файле после сортирвоке появляются непонятные символы.Не мог ли бы исправить.А так ,если английские символы всё отлично.Большое ,спасибо!


Сообщение отредактировано: V.k.l.chr.by -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Проверил ещё раз,всё ровно русские символы не сортируютсяв текстовом файле(непонятные ироглифы),а сама сортирвока в чёрнмом окошке всё нормально.Не помогли ли Вы помочь разобраться?Я так понимаю,чт окажись загвоздка в строке
Код

  CharToOem(str, str);

Так как ,я взял и данную строку закомментировал и уже файл нормально отсортировался,но возникла проблемав черном окошке(непоняные ироглифы)

Сообщение отредактировано: V.k.l.chr.by -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Гость






Цитата
я взял и данную строку закомментировал и уже файл нормально отсортировался,но возникла проблемав черном окошке(непоняные ироглифы)
Ну, так возьми и чуть-чуть подкорректируй 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);
}
}
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Ух..выручили Вы меня всё тепреь работает!!Ура с победой!!Та кже небольшйо вопрос.. а можно задавать вопросы по задачке.Просто как моей помощи мало было.Поэтмоу ,чтобы защитить эту задачку за зачёте,хотелсоь разобрат ькаждую строчку.Так что если будут вопрсоы можно задавать?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Гость






Цитата
Так что если будут вопрсоы можно задавать?
Задавай, конечно... Для этого форум и существует - чтобы помочь разобраться с тем, что непонятно...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


И так мне уже в начале не понятно первые строчки.А именно:"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"А дальше не понял.Но там я та кпонял что-то связано с указателями.Я не очень и так понял про указатели.Если вообщем,то они выделяют память под объект,если так,тогда когда пишем простые программы мы вообще не использовали память.Тогда вопрос,откуда появлялась память,в тех простых программах?


 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Гость







// функция 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);
}
}


Цитата
Тогда вопрос,откуда появлялась память,в тех простых программах?
Ну, если программки были совсем простые, значит все переменные создавались статически, то есть вся необходимая память выделялась еще при компиляции...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #12


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Вообщем всё понятно,но возникли небольшие вопросики.
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/Я ещё раз хочу выразить благодарность за помощь студенту.
-
void sort(char* ptr[], int n_lines) {
for(int i = 0; i < n_lines; i++) {
for(int j = n_lines - 1; j > i; j--) {
if(strcmp(ptr[j - 1], ptr[j]) > 0) {
char *tmp = ptr[j-1];
ptr[j-1] = ptr[j];
ptr[j] = tmp;
}
}
}
}


int main()
{

char s_in_name[] = "Введите путь к файлу : ";
CharToOem(s_in_name, s_in_name);

char s_out_name[] = "Введите путь к отсортированному файлу : ";
CharToOem(s_out_name, s_out_name);

char s_err_open[] = "Ошибка при открытии файла\n";
CharToOem(s_err_open, s_err_open);

char s_before[] = "До сортировки :";
CharToOem(s_before, s_before);

char s_after[] = "После сортировки :";
CharToOem(s_after, s_after);

char in_name[64], out_name[64];

const int maxLines = 1000;
char *ptr[maxLines];


cout << s_in_name;
cin >> in_name;

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];
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;

}
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #13


Гость






Цитата(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-е по Паскалю: Методы сортировок

void sort(char* ptr[], int n_lines) {
for(int i = 0; i < n_lines; i++) {
for(int j = n_lines - 1; j > i; j--) {
if(strcmp(ptr[j - 1], ptr[j]) > 0) {
char *tmp = ptr[j-1];
ptr[j-1] = ptr[j];
ptr[j] = tmp;
}
}
}
}




// а это - основная программа
int main()
{

// Сначала задаем все строковые константы и приводим их к виду,
// в котором они нормально отображаются на экране...

char s_in_name[] = "Введите путь к файлу : ";
CharToOem(s_in_name, s_in_name);

char s_out_name[] = "Введите путь к отсортированному файлу : ";
CharToOem(s_out_name, s_out_name);

char s_err_open[] = "Ошибка при открытии файла\n";
CharToOem(s_err_open, s_err_open);

char s_before[] = "До сортировки :";
CharToOem(s_before, s_before);

char s_after[] = "После сортировки :";
CharToOem(s_after, s_after);

// место для имен входного/выходного файлов
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;

}
По-моему несложно...
 К началу страницы 
+ Ответить 
сообщение
Сообщение #14


Новичок
*

Группа: Пользователи
Сообщений: 29
Пол: Мужской

Репутация: -  0  +


Спасибо.Но и в правду как бы всё понятно.
Так же хочу вернуться к ...
Цитата

Ну, если программки были совсем простые, значит все переменные создавались статически, то есть вся необходимая память выделялась еще при компиляции...

Я как читил,что каждый тип имеет определённый диапозон.Получатеся,если в простых программах этот диапозон нам вполне хватал,то в случае больших программах как в моей,ей болльше потребуеться диапозон и поэтому и нужны указатели.Правильно ли я расcуждаю?
Так же я хотел вашего совета,как всё таки начитсья правильно составлять алгоритмы для решение той или иной программы.Я к чему,к тому что как бы теория понятно,а вот напрактики чтобы это применить не очень получаеться.То ли у меня слабо мышление,или как бы первый курс и надо побольше решать задач,чтобы набратсья опыта.И меня так же заинтересовало,так где же этот тот же метод пузырбка применяеться,ну можетв програамах каких либо.Может частично он применяется в программе тот же "телефонный справочник"где он сортирует фамилии.И так если не трудно прокоментировать характеристики на данной ссылке
http://forum.pascal.net.ru/index.php?act=Attach&type=post&id=986
Читал,что метод пузырька считается самый легкий способ,но и не очень часто он используется он.Может я благодаря этой характеристе и получу на свой ответ,почему он на столько плох.Думаю Вас не загрузил своим дурацкими вопросами.

Сообщение отредактировано: V.k.l.chr.by -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #15


Гость






Дело не в диапазоне... Дело в том, что память в программе может выделяться при компиляции и во время работы. Вот, скажем пример программы, которой тоже вроде бы не нужно многое, но без указателей в ней обойтись нельзя (здесь я бы попросил более опытных программистов не напоминать про продвинутые библиотеки языка, я о них не забыл, помню, что можно и без указателей, но на _таком_ уровне лучше об этом не упоминать, иначе в голове останется только каша...): написать программу, которая получит от пользователя число, организует массив из этого количества элементов, и обрабатывает его... Все просто, правда? Но ты не можешь написать так:

// тут подключение заголовочных файлов
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;
}

Вот тебе и необходимость (вернее одна из необходимостей) использования указателей... Я не буду углубляться в дебри, и не стану говорить ничего про массивы и указатели, про строки - тебе надо бы прочесть какую-нибудь книжку по С++, чтобы понять основы, потом можно будет разговаривать дальше...

Цитата
меня так же заинтересовало,так где же этот тот же метод пузырбка применяеться,ну можетв програамах каких либо
В принципе, он может применяться где угодно - это полноценный метод сортировки, только медленный очень, что и видно из сравнения времени выполнения сортировок разными алгоритмами: сортировка методом "пузырька" выполняется медленнее, чем любым другим методом при любых размерах массивов; чем размер больше, тем отрыв заметнее... Но у него есть и преимущество: он очень простой, и иногда (если надо быстро написать программку, сортирующую небольшой массив) очень даже может использоваться (потому как набирается просто автоматически)...
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 1.12.2020 19:40
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name