Всем добра.
Написал код с возможность добавлять в конец/начало списка, вывод на монитор и удаление необходимого значения, запись/чтение файла. С последним трабл. Вместо того, чтобы аннигилировать необходимые данные, он стирает также все, что находится после этого самого значения, и с файловыми манипуляциями он ругается, когда хочу считать информацию. Не могу разобраться, в чем причина. Код получился громоздким, так что хотел бы услышать критику на его счет, если возможно как-то его оптимизировать/откорректировать, короче, сделать вменяемым, выслушаю с удовольствием. :) Вот сам код:
#include<fstream>
#include<iostream>
using namespace std;
struct foo{
int data;
foo*Next;
};
foo *Head=0;
//добавление в начало списка
void add_start(int val){
foo*pt=new foo;
pt->data=val;
pt->Next=Head;
Head=pt;
}
//вывод на экран
void show(){
foo* p=Head;
while(p){
cout<<p->data;
p=p->Next;
}
cout<<endl;
}
//добавление в конец списка
void add_end(int val){
foo*pt=new foo;
foo*ps=Head;
while(ps){
if(ps->Next==0){ ps->Next=pt;
pt->Next=NULL;
pt->data=val;
}
ps=ps->Next;}
}
//Удаление искомого значения
void search(int val){
foo*psearch=Head;
while(psearch->Next->data!=val){
psearch=psearch->Next;}
psearch->Next=psearch->Next->Next;
psearch->Next->Next=0;
if(psearch->Next==0){
cout<<"This list dont have-"<<val;
}}
//Удаление последнего элемента
void del_tail(){
foo*ptail=Head;
Head=ptail->Next;
ptail=0;
}
//Удаление первого элемента
void del_start(){
foo*pstart=Head;
while(pstart->Next){
if(pstart->Next->Next==0){
pstart->Next=0; }
else {
pstart=pstart->Next;}
}}
//Запись в файл
void write_file(){
foo*pwrite=Head;
ofstream outstrm ("test.txt", ios_base::out);
if(outstrm.is_open())
{
while(pwrite){
outstrm.write(reinterpret_cast<char*>(pwrite), sizeof(char));
pwrite=pwrite->Next;}
}
outstrm.close();
}
//Считывание из файла
void read_file(){
int mass[10];
ifstream outstrm("test.txt");
while(!outstrm .eof()){
outstrm>>mass;
}
outstrm.close();
}
int main(){
add_start(3);
add_start(4);
add_start(5);
add_start(6);
show();
add_end(9);
show();
add_start(11);
show();
del_tail();
show();
del_start();
show();
cout<<"/////////////////";
search(5);
show();
write_file();
read_file();
return 0;}
@dil, в самом деле, функция read_file()
как-то совсем не получилась. Если бы не словесное описание в начале вопроса, то ни за что бы не догадался для чего она предназначена.
Наверное, она должна выглядеть (по крайней мере) как-то так:
void read_file(){
int num;
ifstream in("test.txt");
if (in.good())
while((in >> num;))
add_start(num);
in.close();
}
А знаете, код становится значительно лучше, когда функции более универсальны и могут работать с разными данными. Для этого данные, которыми они оперируют, надо передавать в функции в виде аргументов. Тогда, скажем, add_start()
могла бы выглядеть так:
void add_start (struct foo **head, int n) {
struct foo *item = new struct foo;
item->next = *head;
item->data = n;
*head = item;
}
и использоваться в обновленной read_file
вот так:
/*
Записывает числа из файла <fname> в список <list>
Возвращает false при ошибках
*/
bool readfile (const char *fname, struct foo **list) {
ifstream in(fname);
if (!in.good()) {
cerr << "Can't open " << fname << '\n';
in.close();
return false;
}
int n;
while ((in >> n))
add_start(list, n);
bool rc = in.eof(); // если дошли до конца файла, то все ОК, вернем true
if (!rc) { // какая-то ошибка при чтении очередного числа
in.clear(); // сбросим флаг ошибки для попытки чтения нечисловых данных
string s;
in >> s;
if (in.good())
cerr << "invalid data: [" << s << "] in file: " << fname << '\n';
else
cerr << "file: " << fname << " read error\n";
}
in.close();
return rc;
}
Остальные функции стоит также переделать, чтобы они могли работать с разными списками. Если функция может изменить указатель на начало списка (как это делает add_start()
), то в качестве списка ей надо передавать адрес указателя (часто говорят указатель на указатель).
Если же функция не меняет список, то можно передать адрес элемента списка. Например:
void show_list (struct foo *list) {
for (; list; list = list->next)
cout << list->data << '\n';
}
Кстати, обратите внимание, в таком виде у функции появилось новое свойство. Теперь она может печатать список не только с начала, а с любого (очевидно, найденного ранее) элемента.
Теперь все переменные можно "загнать" в main
и она может выглядеть так (делаем 2 списка из 2-х файлов)
int main (int ac, char *av[]) {
struct foo *head_list1 = 0, *list2 = 0;
if (read_file(av[1] ? av[1] : "test.dat", &head_list1))
show_list(head_list1);
else
cout << "Fail\n";
cout << "---\n";
if (read_file("test.txt", &list2))
show_list(list2);
else
cout << "Fail\n";
}
Что касается остальных функций, то (критики много, времени мало) посмотрите внимательно на то, что у Вас возможны операции доступа по НУЛЕВОМУ указателю. Просто сейчас Вы неявно предполагаете, например, что search()
всегда будет вызываться для непустого списка (а это может быть не так).
Также проверьте, что произойдет, если удаляя хвост Вы удаляете единственный элемент в списке или удаляя искомый, удаляете первый (тот, на который указывает head). В таких случаях значение head (указателя на список) тоже необходимо менять.
В общем, переработайте (с учетом списка, как параметра функций) и если будут еще вопросы, то не стесняйтесь, задавайте (IMHO лучше новой темой, которая может в своей преамбуле ссылаться на эту).
Уважаемый dil . По моему не слишком большому опыту следует по возможности избегать типовых преобразований при помощи оператора приведения типов "reinterpret-cast", который Вы использовали в функции "Записи в файл". Кстати, при записи и чтении файлов такое приведение типа особенно опасно. И ещё. При удалении элементов из списка удобней сделать так, чтобы удаляющие функции просто возвращали значение удалённого элемента, а не принимали в качестве значений имена переменных которым эти значения следует вернуть. Удачи.
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Хочу понять, как пользоваться вокселямиКак всё это работает, представляю, а вот как это выразить в кусочке кода на c++ - не знаю
Есть много сгенерированного кода c++ без использования оператора deleteНужна утилита для автоматического исправления этого, которая бы записывала...
Норма находится как максимальная по модулю сумма элементов строкиВроде что-то распараллелил, процессы подсчитывают суммы, но в цикл нахождения...