Будьте добры,уважаемые форумчане можете исправить ошибку в данном коде программе.Уж очень срочно надо.Буду очень признателен.А вот и само условие и код программы:
Исходные данные находятся в текстовом файле. Разделитель – конец строки. Программа запрашивает имя входного и результирующего (отсортиро-ванного) файла. Использовать динамическое распределение памяти.И надо сортировать строки методом пузырька.Тут как бы всё правилььно выполняет,только вот пишет ошибку .. и как мне подсказывали что-то с указателями.Или после кода программы"void main(void)..."
#include<stdio.h>P.S.Прошу прощение,за повтор темы.Хотел удалить ,но не нашёл.
#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);
}
Можно уточнить? зачем понадобилось перемешивать чистый С и C++ (ну, например, работать в одной программе и с FILE* и с потоками) ? Если у тебя С++, то работай с ifstream/ofstream, это ж проще гораздо...
К тому же С++ не позволяет делать void main(), функция main должна возвращать результат типа int...
А вот это:
char *nam = new char[];
Вообщем я просто брал нечто похожую программу с лабораторной работы и вставлял и вышел такой просяк.Да и где-то помогали мне.Так что решил когда заработает программа,тогда и каждую строчку попробую разобраться.А сортироватьться строки будут по буквам как в словари.Тоетсь первая буква перовй строки с второй строки первой буквы.
#include <windows.h>В принципе, тут можно было обойтись вообще десятком строк для сего, что делается в программе, но ты сам хотел char* и динамическое выделение памяти...
#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;
}
Просто в условии дано ,чтобы было динамичесткое распределение памяти.Что ж кажись всё правильно.Только вот ,если русские символы в текстовом файле находяться,то в новом файле после сортирвоке появляются непонятные символы.Не мог ли бы исправить.А так ,если английские символы всё отлично.Большое ,спасибо!
Проверил ещё раз,всё ровно русские символы не сортируютсяв текстовом файле(непонятные ироглифы),а сама сортирвока в чёрнмом окошке всё нормально.Не помогли ли Вы помочь разобраться?Я так понимаю,чт окажись загвоздка в строке
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);
}
}
Ух..выручили Вы меня всё тепреь работает!!Ура с победой!!Та кже небольшйо вопрос.. а можно задавать вопросы по задачке.Просто как моей помощи мало было.Поэтмоу ,чтобы защитить эту задачку за зачёте,хотелсоь разобрат ькаждую строчку.Так что если будут вопрсоы можно задавать?
И так мне уже в начале не понятно первые строчки.А именно:"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"А дальше не понял.Но там я та кпонял что-то связано с указателями.Я не очень и так понял про указатели.Если вообщем,то они выделяют память под объект,если так,тогда когда пишем простые программы мы вообще не использовали память.Тогда вопрос,откуда появлялась память,в тех простых программах?
// функция 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);
}
}
Вообщем всё понятно,но возникли небольшие вопросики.
1-Почему,в коде программы нельзя было просто написать до N,а не n_lines?
2-И у Вас в комментарии написано,что "до n_lines - 1"Причём тут единица.
3-И если не трудно,можно ещё пару слов об "os"ЧТо это такое?Я как понял,это назваине потока,благодаря чему будет копироваться троки в файл.Я так понял?
-
// для всех номеров строк от 0 до n_lines - 1 (в С++ индексация всегда начинается с 0)
for(int i = 0; i < n_lines; i++) {
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;
}
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;
}
Спасибо.Но и в правду как бы всё понятно.
Так же хочу вернуться к ...
Дело не в диапазоне... Дело в том, что память в программе может выделяться при компиляции и во время работы. Вот, скажем пример программы, которой тоже вроде бы не нужно многое, но без указателей в ней обойтись нельзя (здесь я бы попросил более опытных программистов не напоминать про продвинутые библиотеки языка, я о них не забыл, помню, что можно и без указателей, но на _таком_ уровне лучше об этом не упоминать, иначе в голове останется только каша...): написать программу, которая получит от пользователя число, организует массив из этого количества элементов, и обрабатывает его... Все просто, правда? Но ты не можешь написать так:
// тут подключение заголовочных файлов
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;
}