русский
Germany.ruForen → Архив Досок→ Webdesign und Hosting

C++

336  1 2 alle
ойМОЛОДой местный житель10.02.05 16:27
ойМОЛОДой
10.02.05 16:27 
Пишу в Borland Builder.
Маленькая функция:

FILE *fp;
char LaName[256];
AnsiString Pfad = GetCurrentDir() + "\\data.dat";
fp = fopen(Pfad.c_str(), "r",0);
if (fp != NULL)
{
fscanf(fp, "%s", &LaName,0);
...
...
}
fclose(fp,0);

Т.е. считываю кой-чего из текстового файла, в котором имеется, скажем, просто строка текста.
Проблема: почему текст считывается только до первого пробела? И, разумеется, как это исправить?
Это вообще ещ╦ не готовая функция, спотыкаюсь в самом начале...
Для чего это нужно?..
Смысл такой. Имеется текст, состоящий из строк с таким содержанием:
имя (разделитель) фамилия (разделитель) возраст
Ну это, например. Содержание не так важно.
Нужно записать это вс╦ в массив.
Идея ещ╦ была вот такая:

fscanf(fp, "%s %s %d", &FiName, &LaName, &Age,0);

Но не знаю, как вставить разделитель. Выискал функцию strtok(), но тоже что-то толку нет. В общем, впору кричать "караул".
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#1 
gendy коренной житель10.02.05 16:44
gendy
NEW 10.02.05 16:44 
in Antwort ойМОЛОДой 10.02.05 16:27
а почему такую неудачную функцию выбрал? fscanf читает только до конца строки.
читай с fread.
а второе лучше структурой делать
struct Data
{
char FiName[100];
char LaName[100];
int Age;
};
Помни, ковчег был построен любителем. Профессионалы построили "Титаник".

Фашизм будет разбит


Человека карают только те боги, в которых он верит

#2 
ойМОЛОДой местный житель10.02.05 16:51
ойМОЛОДой
NEW 10.02.05 16:51 
in Antwort gendy 10.02.05 16:44
Ну вот не читает оно у меня до конца строки. Как ни крутил. Понять не могу...
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#3 
gendy коренной житель10.02.05 17:06
gendy
NEW 10.02.05 17:06 
in Antwort ойМОЛОДой 10.02.05 16:51
бери fread и не морочь себе голову.
есть ещ╦ интересный способ - с использованием
TIniFile
Помни, ковчег был построен любителем. Профессионалы построили "Титаник".

Фашизм будет разбит


Человека карают только те боги, в которых он верит

#4 
ойМОЛОДой местный житель10.02.05 17:12
ойМОЛОДой
NEW 10.02.05 17:12 
in Antwort gendy 10.02.05 17:06
Да, про INI я знаю. Но надо именно без него.
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#5 
ойМОЛОДой местный житель10.02.05 17:20
ойМОЛОДой
NEW 10.02.05 17:20 
in Antwort gendy 10.02.05 17:06
Ок, взял fread(), теперь только не пойму, как мне строку от строки отделить. Можно для дураков ещё раз объяснить, если не сложно?
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#6 
gendy коренной житель10.02.05 17:21
gendy
NEW 10.02.05 17:21 
in Antwort ойМОЛОДой 10.02.05 16:51
а как оно читать будет, если переменная заканчивается нул╦м, вот он до нуля читает и хватит. если хочешь использовать fscanf - читай каждую переменную по раздельности
Помни, ковчег был построен любителем. Профессионалы построили "Титаник".

Фашизм будет разбит


Человека карают только те боги, в которых он верит

#7 
ойМОЛОДой местный житель10.02.05 17:21
ойМОЛОДой
NEW 10.02.05 17:21 
in Antwort gendy 10.02.05 17:06
Есть вот такая идея. Записать данные в файл в виде:
имя, фамилия, возраст;
имя, фамилия, возраст;
...
Потом можно будет с помощью чего-нибудь типа index() их разделить. Так?
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#8 
ойМОЛОДой местный житель10.02.05 17:23
ойМОЛОДой
NEW 10.02.05 17:23 
in Antwort gendy 10.02.05 17:21
В ответ на:

а как оно читать будет, если переменная заканчивается нулём, вот он до нуля читает и хватит. если хочешь использовать fscanf - читай каждую переменную по раздельности


теперь догнал, что к чему в этой fscanf(). спасибо!
Только тогда уж я лучше в самом деле fread() возьму.
"...вечно молодой, вечно пьяный..."

[син]"...вечно молодой, вечно пьяный..."[/син]
#9 
gendy коренной житель10.02.05 17:29
gendy
NEW 10.02.05 17:29 
in Antwort ойМОЛОДой 10.02.05 17:21
Есть вот такая идея. Записать данные в файл в виде:
имя, фамилия, возраст;
имя, фамилия, возраст;
...

структуру бери
Помни, ковчег был построен любителем. Профессионалы построили "Титаник".

Фашизм будет разбит


Человека карают только те боги, в которых он верит

#10 
digital_pilot der Mann von der Panzerwiese10.02.05 17:29
NEW 10.02.05 17:29 
in Antwort ойМОЛОДой 10.02.05 17:23
или стрим.
#include<fstream.h>
char name [100], firstname [100];
int age;
ifstream src;
src.open("D:\\myfile.txt",ios::nocreate,0);
while (!src.eof()) {
src>>name>>firstname>>age;
cout<<name<<" "<<firstname<<" "<<age<<"\n";
}
--------------
Авиатор х#ев
#11 
Murr местный житель10.02.05 19:02
Murr
NEW 10.02.05 19:02 
in Antwort ойМОЛОДой 10.02.05 16:51
Ну вот не читает оно у меня до конца строки.
---------------
Читает [f]gets(), a через [f]scanf надо правильно задавать параметры - там их 5 штук - все читается.
#12 
Murr местный житель10.02.05 19:07
Murr
NEW 10.02.05 19:07 
in Antwort gendy 10.02.05 17:29
на самом деле - почти без разницы.
fscanf может читать текстовый, невыровненый файл,
а для fread нужно будет подгонять двоичный формат, включая последнее число

#13 
Murr местный житель10.02.05 19:13
Murr
NEW 10.02.05 19:13 
in Antwort digital_pilot 10.02.05 17:29, Zuletzt geändert 10.02.05 19:18 (Murr)
Если уж говорить об ПлюсАх...
class Data
{
public:
Data() {...};
~Data() {...};
protected:
virtual ifstream& operator>>(ifstream&) {...}
virtual ofstream& operator<<(ofstream&) {...}
private:
char FiName[100];
char LaName[100];
int Age;
}
Да?
#14 
Murr местный житель10.02.05 19:17
Murr
NEW 10.02.05 19:17 
in Antwort ойМОЛОДой 10.02.05 16:27
Пишу в Borland Builder.
------------
Не заметил.
Базу в Аксесе, таблицу с полями, дальше - коннектион к базе и навигация через методы таблицы.
То, об чем ты спрашиваешь - стандартный Си, фактически уже лет 10 как почти мертвое.
#15 
digital_pilot der Mann von der Panzerwiese10.02.05 19:19
NEW 10.02.05 19:19 
in Antwort Murr 10.02.05 19:13
ну, если товарищ заодно хочет подзарулить в дебри ООП.... А вообще (если под виндоуз), затея со считыванием текстовых таблиц заданного формата своими самопальными парсерами мне никогда не нравилась. Есть ADO, есть MS Jet - это работа для них :)))
--------------
Авиатор х#ев
#16 
Murr местный житель10.02.05 19:20
Murr
NEW 10.02.05 19:20 
in Antwort digital_pilot 10.02.05 19:19
Если только длина строк не переменна.
#17 
digital_pilot der Mann von der Panzerwiese10.02.05 19:23
NEW 10.02.05 19:23 
in Antwort Murr 10.02.05 19:20
какая разница. Можно и переменной. Semicolon-separated, tab-separated, CSV - Jet сожрет.
--------------
Авиатор х#ев
#18 
Murr местный житель10.02.05 19:33
Murr
NEW 10.02.05 19:33 
in Antwort digital_pilot 10.02.05 19:23
имелся в виду "не плоский" файл, когда строки не равны по количеству полей и содержат инфу об полях.
строка 1: [ФИГ]фамилия имя год
строка 2: [CAR]зеленая
#19 
digital_pilot der Mann von der Panzerwiese10.02.05 19:45
NEW 10.02.05 19:45 
in Antwort Murr 10.02.05 19:33
гм... ну это уже другое дело. Поэтому я и написал "заданного формата" ;)
--------------
Авиатор х#ев
#20 
ойМОЛОДой местный житель10.02.05 21:07
ойМОЛОДой
NEW 10.02.05 21:07 
in Antwort Murr 10.02.05 19:02
В ответ на:

Ну вот не читает оно у меня до конца строки.
---------------
Читает [f]gets(), a через [f]scanf надо правильно задавать параметры - там их 5 штук - все читается.


Ну вот что за народ такой??? Я потому сюда и пришёл, что сам разобраться не смог и никакой хэлп не помог. Нет чтоб рассказать и объяснить хотя бы на примере, начинаются высказывания типа "я умный, а ты - бестолочь." Покажи мне хоть одного, кто сразу всё мог!!!
ПыСы: убедительная просьба не отвечать на это сообщение. я ветку не для этого открыл. спасибо!
"...вечно молодой, вечно пьяный..."

[син]"...вечно молодой, вечно пьяный..."[/син]
#21 
ойМОЛОДой местный житель10.02.05 21:09
ойМОЛОДой
NEW 10.02.05 21:09 
in Antwort digital_pilot 10.02.05 17:29
Такого зверя я ещё не видел. Попробую разобраться. Спасибо!
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#22 
ойМОЛОДой местный житель10.02.05 21:10
ойМОЛОДой
NEW 10.02.05 21:10 
in Antwort gendy 10.02.05 17:29
Уже убедился, что фигню не посоветуешь. Посмотрим, чего из насоветованного в итоге получится, потом напишу.
"...вечно молодой, вечно пьяный..."
[син]"...вечно молодой, вечно пьяный..."[/син]
#23 
Murr местный житель10.02.05 21:35
Murr
NEW 10.02.05 21:35 
in Antwort ойМОЛОДой 10.02.05 21:07
"я умный, а ты - бестолочь."
-------------
Меня в плохих подсказках обвиняли достаточно часто. Выработалось
отсутствие реакции на подобные обвинения. Тем более, что те кто у
меня учился умеют делать эту работу и делают ее самостоятельно.
сам разобраться не смог и никакой хэлп не помог
-------------
По-этому тебе и подсказали в каком направлении копать в хелпе -
функция fscanf() и ПЯТЬ спецификаций в формате.
Подсказка вторая - ПРОБЕЛ - это тоже информация. Если не поможет -
рисуй строку на бумаге в клеточку и постарайся понять сколько
информации считывается по каждому спецификатору формата и что
будет следующим на входе.
#24 
scorpi_ студент13.02.05 16:01
NEW 13.02.05 16:01 
in Antwort digital_pilot 10.02.05 17:29
#include<fstream.h>
ifstream src;


Sorry, но по стандарту, действительному с 1998 года, писать надо

#include <fstream>
std::ifstream src;


veni, vidi... expuli

#25 
scorpi_ студент13.02.05 16:15
NEW 13.02.05 16:15 
in Antwort Murr 10.02.05 19:13
С двумя замечаниями:
1. char FiName[100]; char LaName[100];
вместо char[] следует использовать std::string
2.
protected:
virtual ifstream& operator>>(ifstream&) {...}
virtual ofstream& operator<<(ofstream&) {...}
С какой стати они protected? Операторы ввода вывода обычно используются другими классами, и во-вторых их никогда не следует делать членами класса - это препятствует соединению ряда таких операторов в цепь.
veni, vidi... expuli
#26 
Murr местный житель13.02.05 16:25
Murr
NEW 13.02.05 16:25 
in Antwort scorpi_ 13.02.05 16:15
С двумя замечаниями:
1. char FiName[100]; char LaName[100];
вместо char[] следует использовать std::string
------------------
Можно обойтись и char *, если понимать что будет дальше.
К тому же, если вспомнить что это пишется под СБилдером,
можно и AnsiString задействовать...
2.
protected:
virtual ifstream& operator>>(ifstream&) {...}
virtual ofstream& operator<<(ofstream&) {...}
С какой стати они protected? Операторы ввода вывода обычно используются другими классами, и во-вторых их никогда не следует делать членами класса - это препятствует соединению ряда таких операторов в цепь.
--------------------
Старая привычка. Еще с тех времен, когда IO было friend.
#27 
scorpi_ студент13.02.05 16:37
NEW 13.02.05 16:37 
in Antwort Murr 13.02.05 16:25
Можно обойтись и char *, если понимать что будет дальше.
Можно, но не нужно (пример можно, где это оправдано?). И тем более нет смысла употреблять char* отвечая новичку.
можно и AnsiString задействовать...
Опять же, можно, но не нужно. Лучше насколько это возможно использовать стандарт.
veni, vidi... expuli
#28 
Murr местный житель13.02.05 16:53
Murr
NEW 13.02.05 16:53 
in Antwort scorpi_ 13.02.05 16:37
Можно, но не нужно (пример можно, где это оправдано?).
-------------------------
Хммм... Последний раз это делал, когда надо было в довольно большом
проекте встроить контроль вывода и при этом существующий код не
должен был меняться. Пришлось дополнить структуру FILE и переопределить f*().
И тем более нет смысла употреблять char* отвечая новичку.
--------------------------
По-этому там и оставлены char[100], чтобы не возникало непонятных
вопросов.
Опять же, можно, но не нужно.
Лучше насколько это возможно использовать стандарт.
-------------------------
Не всегда. Если вместо полностью соответствующей стандарту прожки
в 400 строк, можно написать не-стандарт на 40, то нет смысла писать
стандарт.
#29 
scorpi_ студент13.02.05 17:13
NEW 13.02.05 17:13 
in Antwort Murr 13.02.05 16:53
Если вместо полностью соответствующей стандарту прожки в 400 строк, можно написать не-стандарт на 40, то нет смысла писать стандарт.
Можно пример этих 40 строк? Я утверждаю, что моя standard-conform программа не будет существенно отличаться по длине.
veni, vidi... expuli
#30 
Murr местный житель13.02.05 17:53
Murr
NEW 13.02.05 17:53 
in Antwort scorpi_ 13.02.05 17:13
Можно пример этих 40 строк?
---------------
А смысл? Функциональность там все одно будет близкой к нулю и
портировать это не придется.
Кстати, тот код, что приведен автором вопроса, на 95% рабочий. То,
что там нужно добавить три строки - пустяки и не играет никакой роли.
А сравнивать надо именно с тем, что приведено тобой в качестве
стандарта - будет как раз 1:10 по объему.
#31 
scorpi_ студент13.02.05 18:01
NEW 13.02.05 18:01 
in Antwort Murr 13.02.05 17:53
Стандартный С++ по объёму будет как раз меньше.
veni, vidi... expuli
#32 
scorpi_ студент13.02.05 18:25
NEW 13.02.05 18:25 
in Antwort ойМОЛОДой 10.02.05 16:27
Во-первых, если у Вас строка типа Петров Иван 45, то вызов функции должен выглядеть следующим образом: fscanf( fp, "%s %s %d\n", &lastname, &name, &age ,0); Но, в реальной жизни эту функцию лучше не использовать, так как fscanf копирует поля в переменные не проверяя достаточен ли размер буфера, то есть с этой функцией очень легко получить buffer overflow. Если Вам надо прочитать строку, то используйте fgets, с дальнейшей разбивкой строки на поля с помощью strtok, strchr и других функций из strng.h, с дальнейшей проверкой полученных полей.
Но, вс╦ вышесказанное собственно говоря неважно, так как Вы написали в заголовке С++, в то время как вс╦ вышесказанное относится к С. Я Вам очень порекомендую почитать книгу для начинающих по С++, например Accelerated C++ Энди К╦нига. И кроме того, пользуйтесь насколько это возможно стандартным С++. В данном случае std::string, std::ifstream и так далее.
В С++ стиле Ваша задача будет выглядеть примерно так:
#include <cstdlib>
#include <string>
#include <fstream>
#include <deque>
template< class ch, class tr, class al >
std::deque<std::basic_string<ch, tr, al> > split( const std::basic_string<ch, tr, al>& line, const ch* space )
{
std::deque< std::basic_string<ch, tr, al> > v;
for ( std::basic_string<ch, tr, al>::size_type end = 0,
begin = line.find_first_not_of( space, end ,0);
begin != std::basic_string<ch, tr, al>::npos;
begin = line.find_first_not_of( space, end ) )
{
end = line.find_first_of( space, begin ,0);
if ( end == std::basic_string<ch, tr, al>::npos )
v.push_back( line.substr( begin ) ,0);
else
v.push_back( line.substr( begin, end - begin ) ,0);
}
return v;
}
class Person
{
std::string name_;
std::string lastname_;
int age_;
public:
Person( const std::string& line ) : age_(0)
{
std::deque<std::string> v = split( line, " " ,0);
if ( v.size() != 3 )
throw std::runtime_error( "invalid line" ,0);
name_ = v[0];
lastname_ = v[1];
age_ = atoi( v[2].c_str() ,0);
}
const std::string& name() const { return name_; }
const std::string& lastname() const { return lastname_; }
int age() const { return age_; }
};
int main()
{
std::deque< Person > students;
std::ifstream students_file( "data.dat" ,0);
while( students_file.good() && !students_file.eof() )
{
std::string buffer;
std::getline( students_file, buffer ,0);
students.push_back( Person( buffer ) ,0);
}
}


И наконец - хотя и бывают ситуации, когда текст файлы можно использовать, но вс╦ же почитайте книжки по базам данных.
veni, vidi... expuli

#33 
Murr местный житель13.02.05 18:30
Murr
NEW 13.02.05 18:30 
in Antwort scorpi_ 13.02.05 18:01
Ну хорошо, уговорил.
СБилдер 5(6). Строим МИДАС-сервер на базе RemoteDataModule.
Если не знаешь, то там идет обмен пакетами - на клиента
уходит полный набор, а возвращается дельта-пакет -
изменено, удалено, новое.
Со стороны базы весь доступ идет через процедуры - там
их 4 штуки и они вполне согласованы по параметрам.
Дополнительно - сделан базовый класс (на базе RemoteDataModule)
c функцией переброски полей из пакета в параметры процедур.
Ну разумеется где не надо не перебрасывается первичный ключ.
Размер кода, не считая *.h, как раз примерно 40 строк - один
switch на три позиции.
Будем строить что-то похожее на базе STL&STD?
Только перед тем как строить вспомни об двух вещах:
- СБилдер базируется на VCL(Паскаль)
- имет RTTI
#34 
scorpi_ студент13.02.05 18:50
NEW 13.02.05 18:50 
in Antwort Murr 13.02.05 18:30
Ты бы ещё VB компоненту упомянул. Всё остальное в данной программе нельзя написать на стандатных плюсах? Короче говоря кончай флеймить.
veni, vidi... expuli
#35 
Murr местный житель13.02.05 18:56
Murr
NEW 13.02.05 18:56 
in Antwort scorpi_ 13.02.05 18:50
В том то и дело, что в СБилдере все пишется в Плюсах, но далеко не в
Стандартных Плюсах, что имеет свои большие плюсы и некоторые
минусы.
А что такое VB компонента?
#36 
Chipolino знакомое лицо19.02.05 13:02
NEW 19.02.05 13:02 
in Antwort scorpi_ 13.02.05 18:25
В ответ на:

Во-первых, если у Вас строка типа Петров Иван 45, то вызов функции должен выглядеть следующим образом: fscanf( fp, "%s %s %d\n", &lastname, &name, &age ,0);



По моему lastname name , без & т.к. уже адресса на начало массива char

#37 
scorpi_ скептик19.02.05 17:07
NEW 19.02.05 17:07 
in Antwort Chipolino 19.02.05 13:02
Да, заглянул в стандарт, согласно нему ты прав, правда мой вариант тоже работает. Но суть собственно не в этом, а в том, что эту функцию можно использовать только в том случае, если ты стопроцентно уверен в том, что все поля в файле не длиннее твоих переменных.
#38 
Murr местный житель20.02.05 00:06
Murr
NEW 20.02.05 00:06 
in Antwort scorpi_ 19.02.05 17:07
Твой вариант "работает" только потому, что в прототипе финкции указано,
что не надо проверять соответствии числа и типов параметров. Для Плюсов,
как и для Паскаля, это нонсенс...
К тому же - не все компиляторы правильно обрабатывают этот код, опуская
операцию получения адреса.
#39 
1 2 alle