LINUX.ORG.RU

Как правильно считывать данные из файла?

 ,


0

2

Предельно простая задача — считать кучу данных из файла, имя которого вводит пользователь.

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
    //some code

    ifstream file1;
    ifstream file2;
    ifstream file3;
    ifstream file4;
    ofstream f1, f2, f3, f4;
    f1.open("output1.txt");
    f2.open("output2.txt");
    f3.open("output3.txt");
    f4.open("output4.txt");
    char* fname1;
    char* fname2;
    
    //some code
    cout<<"Vvedite imya faila "<<(i+1)<<" s dannymi s kanala 340"<<endl;
    cin>>fname1;
    //И ТУТ ПРОГА ПАДАЕТ!!!
    
    file1.open(fname1);
    
  

    //some code

    return 0;
}

Что я делаю не так?

★★

Последнее исправление: CYB3R (всего исправлений: 3)
Ответ на: комментарий от Eddy_Em

в пхп, питоне и т.п. — да. нынешние кодеры даже не думают заглядывать в матчасть

anonymous
()

Не инициализирована переменная fname1 и не выделена память

ms-dos32
()
 cout<<"Vvedite imya faila "<<(i+1)<<" s dannymi s kanala 340"<<endl;

Где объявлено i?

cin>>fname1;
Куда пишем?

CrossFire ★★★★★
()

В с++ следует использовать std::string вместо char * для строковых операций. Вообще, «*» должно встречаться как можно реже.

note173 ★★★★★
()

char* fname1;

Ну, я, конечно, не кодил уже с полгода, но все же создания указателя явно недостаточно.

Надо сделать что-то типа char *fname1 = new char что-то там.

Ну или * убрать.

Могу ошибаться.

Zhbert ★★★★★
()
Ответ на: комментарий от Zhbert

char fname[N] или char * fname = new char[N], емнип. а можно malloc'ом выделить в fname

xapienz
()

Давно не было такого трагизма в девел`опменте.

//И ТУТ ПРОГА ПАДАЕТ!!!

anonymous
()

Надо было выделять память для char *. Или просто использовать char fname[128] (или сколько памяти надо).

Управление памятью в Сях - штука такая... надо или вручную выделять статически, или самому следить, сколько выделять... а то если не хватит, будет плохо, например, «И ТУТ ПРОГА ПАДАЕТ».

Во всяких языках по типу питона какой-нить file.readline() попросту возвращает строку в return, и ничего выделять не надо. Может, в плюсовой библиотеке что-то похожее есть, что _возвращает_ значения из входного потока.

А cin просто выдаёт какие-то значения на выход... но память для переменной приходится выделять вручную.

BattleCoder ★★★★★
()
Ответ на: комментарий от BattleCoder

Или просто использовать char fname[128] (или сколько памяти надо).

А после таких советов в программах появляются уязвимости переполнения буфера, да или просто программа упадёт, если 128 байт не хватит.

gentoo_root ★★★★★
()
Ответ на: комментарий от note173

В с++ следует использовать std::string вместо char * для строковых операций. Вообще, «*» должно встречаться как можно реже.

например под виндой пишут драйвера на c++ какой нафик std::string ? а вообще меня просто бесит std::string как только представлю насколько он толсто и жирно устроен

anonymous
()
Ответ на: комментарий от anonymous

Да ладно, это очень простой и быстрый контейнер, просто выглядит так из-за обобщенности.

note173 ★★★★★
()
Ответ на: комментарий от anonymous

а вообще меня просто бесит std::string как только представлю насколько он толсто и жирно устроен

Для задач, где std::string слишком жирен, есть Pure C.

Dragon59 ★★
()
Ответ на: комментарий от anonymous

и не только под вендой.. а std::string вполне удобная штука

nic11
()

Что я делаю не так?

Ты всё делаешь так, из тебя выйдет хороший php-шник. А C++ для лузеров и старперов.

anonymous
()
Ответ на: комментарий от BattleCoder

я просто на самом деле не знаю, как правильно поступить в данной ситуации... а как? :)

Нужно считывать в ограниченный динамически выделенный буфер какой-нибудь функцией, которая умеет ограничение максимальной длины входных данных (например, fgets или read). Если данные ещё остались, то сделать realloc для буфера, чтобы увеличить его размер (на константу или в некоторое число раз, или другим алгоритмом).

Примеры кода есть здесь: http://sucs.org/Knowledge/Help/Program Advisory/Reading an arbitrarily long l... (то, о чём говорил я, там в самом конце, другие способы — всё равно обёртки над этим).

gentoo_root ★★★★★
()
Ответ на: комментарий от gentoo_root

Если данные ещё остались, то сделать realloc для буфера, чтобы увеличить его размер (на константу или в некоторое число раз, или другим алгоритмом).

… и продолжать читать дальше, естественно.

gentoo_root ★★★★★
()
Ответ на: комментарий от yura_ts

И да, я недосмотрел. Изначальная задумка — [code]char* fname1 = new char[255];[/code], но я не выспавшийся был. Вообще, тему снести можно, а то позор ведь.

yura_ts ★★
() автор топика
Ответ на: комментарий от anonymous

например под виндой пишут драйвера на c++

WUT???

anonymous
()
Ответ на: комментарий от yura_ts

Осталось добавить разве что

free(fname1);
fname1 = NULL;
после того, как fname1 больше не будет использоваться.

gag ★★★★★
()
Ответ на: комментарий от gentoo_root

Ааа. ну понятно. в принципе такая мысль в голове и крутилась.

Получается, какой-нибудь cin использовать потенциально опасно. Хотя его наверное можно использовать с std::string - надо попробовать, это должно быть безопасно... Ну я обычно использовал getline()

а fscanf(«%s»,pointer), получается, тоже использовать нельзя...

А вообще писать на сях - дело неблагодарное =) если нужен надёжный код, лучше использовать ЯП, в котором тяжело выстрелить себе в ногу.

BattleCoder ★★★★★
()
Ответ на: комментарий от BattleCoder

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

yura_ts ★★
() автор топика
Ответ на: комментарий от yura_ts

ок. вам виднее.

советую на будущее для таких случаев, когда будет время - подучить python. лучшее решение, когда нужно «быстро написать, шоб работало».

BattleCoder ★★★★★
()
Ответ на: комментарий от BattleCoder

Ещё проблема — вот такой код:

double x1[1000];
double x2[1000];
n1 = 0;
n2 = 0;

cout<<"Vvedite imya faila s rezultatami pervoi serii"<<endl;
cin>>fname1;
cout<<"Vvedite imya faila s rezultatami vtoroi serii"<<endl;
cin>>fname2;
file1.open(fname1);
file2.open(fname2);
i=0;
while(!file1.eof())
{
file1>>x;
n1++;
cout<<x<<" ";
x1=x;
i++;
}
i=0;
while(!file2.eof())
{
file2>>x;
n2++;
cout<<x<<" ";
x2=x;
i++;
}
нормально записывает данные в первый массив, а во второй последнее значение записывается два раза. Почему?

Да, заранее известно, что 1000 элементов массива точно хватит.

yura_ts ★★
() автор топика
Ответ на: комментарий от yura_ts

ох, мама.

вообще не хорошо называть переменные x1,x2 и т.п. =) ну эт ладно. это мелочь.

малость смущает, что вы зачем-то делаете x1 = x и x2 =x, вместо того, чтобы, например, напрямую записывать в x1/x2.

И, кстати, x вообще где определена? это double или указатель на double?

почитайте как правильно работать с указателями - у вас там путаница... вообще обращаться к массиву по значения надо x = <что-то>

BattleCoder ★★★★★
()
Ответ на: комментарий от keyran

Надо:

x2[i]=x;

В любом случае, повторяющийся код лучше вынести в функцию.

keyran ★★
()
Ответ на: комментарий от yura_ts
x1 = []
x2 = []
n1 = 0
n2 = 0

fname1 = input('Vvedite imya faila s rezultatami pervoi serii')
fname2 = input('Vvedite imya faila s rezultatami vtoroi serii')

file1 = open(fname1,'r')
file2 = open(fname2,'r')

for x in file1:
    x1.append(x)

for x in file2:
    x2.append(x)

Как-то так. Это если каждое новое число в отдельной строке.

Ну, если как-то по-другому, то последние 4 строчки чуток переделать... это я вам поручаю сделать самостоятельно :)

BattleCoder ★★★★★
()
Ответ на: комментарий от BattleCoder

А, ну ещё забыл n1++ и n2++ добавить. думаю, догадаетесь, куда ;)

BattleCoder ★★★★★
()
Ответ на: комментарий от BattleCoder

Я про другой кусок, где в массив, по идее, должна запись идти.

keyran ★★
()
Ответ на: комментарий от BattleCoder

Это потому, что я включил tex-овский режим ввода.
На самом деле там x1=x;
Но из-за вышеуказанного, проглотилось при отправке комментария.

yura_ts ★★
() автор топика
Ответ на: комментарий от BattleCoder

расскажи это тс. во-вторых, ю каннот инто лоркод

anonymous
()
Ответ на: комментарий от BattleCoder

Получается, какой-нибудь cin использовать потенциально опасно.

Если в std::string считывать, то всё точно будет ОК.

а fscanf(«%s»,pointer), получается, тоже использовать нельзя...

По ссылке было написано про спецификатор %as (расширение glibc), который позволяет scanf'у самому выделить память. Но это не портабельно.

gentoo_root ★★★★★
()
Ответ на: комментарий от BattleCoder

В любом языке легко выстрелить себе в ногу. И плюсы как раз наоборот лучше в этом отношении - если в python или objective c программа вдруг внезапно перестаёт работать после обновления минорной версии Qt или какой-то глупости в одной из веток графа выполнения программы, которую никто не заметил при тестах, то в хорошо, любовно написанном C++ коде куча возможных ошибок и выстрелов в ногу отсекаются ещё на компиляции.

C++ - это си с классами. От си у него остались прямая работа с указателями и отсутствие каких-либо встроенных проверок при компиляции, что так часто соблазняет любителей экономить на спичках. Классы, шаблоны и прочие привнесли возможность проверок, но для этого классы ещё нужно использовать.

std::cin, std::string - классовые обёртки, и не рассчитаны на слепую работу с указателями. Если использовать только их, то всё будет ок; правда, если программа обрабатывает мегабайты текста в секунду, то потоковый ввод начнёт тормозить.

fscanf(«%s»,pointer) использовать нельзя, но можно fscanf(«%255s»,pointer), если размер буфера pointer составляет 256 символов. К слову, fscanf вернёт количество считанных символов, так же как и линуксовый системный вызов read(...)

А вообще следует проникаться книгами Страуструпа, а затем и Александреску или Мак-Коннела.

anonymous
()
Ответ на: комментарий от anonymous

Вангую mingw и опции -finput-charset -foutput-charset. Всегда спасало, позволяло один исходик под линуксом превратить в utf-8, под виндой - в кошерный ibm866

anonymous
()
Ответ на: комментарий от gentoo_root

Нужно считывать в ограниченный динамически выделенный буфер какой-нибудь функцией, которая умеет...

Если такие проблемы с буферами - нечего давать их вводить?

char answer='n';
int fileN = 0;
cout << "\nWelcome to user-friendly series processor!";
while (answer !='y') {
  if (fileN >= 9999) {
    fileN = 0;
    cout << "\nPossible mistake?  Corrected!";
  }
  cout << "\nRecord series in file out" << fileN << "[y/?]: ";
  cin >> answer;       
}
// Далее формируем имя файла типа out0000
vahtu
()

Писал бы на С — вряд ли задавал бы такие глупые вопросы.

Хотя, кого я пытаюсь обмануть…

theNamelessOne ★★★★★
()

Правильно использовать для таких задач какой-нибудь нормальный язык.

anonymous
()
Ответ на: комментарий от BattleCoder

Или просто использовать char fname[128] (или сколько памяти надо).

Не учи плохому :)

slackwarrior ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.