Другое > Hard'n'Soft
Програмирование на C++
<< < (22/25) > >>
HoRRoR:

--- Цитата ---HoRRoR,нет, слово app слишком вошло в обиход (в виде сокращения от application) и найти ответ было сложно. Спасибо за ответ.
--- Конец цитаты ---
А кто ищет подобные слова по отдельности, не уточняя контекст? Достаточно написать в запросе C++ ios app.


--- Цитата ---Будет выведено всё без переводов строки? Ведь символьная переменная вполне может принимать значение \n так в чём же проблема?
--- Конец цитаты ---
Открой в бинарном режиме.
gepar:

--- Цитата: HoRRoR ---Открой в бинарном режиме.
--- Конец цитаты ---

--- Код: ---int main()
{
    ifstream file;
    file.open("test.txt", ios::binary);
    if(!file)
     exit(100500);
    char c;
    while(file>>c)
     cout<<c;
    file.close();
    return 0;
}

--- Конец кода ---
Всё равно всё в ряд пишет без пробелов и переводов строк.

Добавлено позже:
И ещё хотел спросить

--- Код: ---    string a="test string";
    const char *b=a.data();
--- Конец кода ---
Получается при вызове строка.data() создаётся массив указателей с содержимым как у строки (это я выгуглил), но зачем его сделали обязательно const тогда? Всё равно это ведь копия, которая потом никак не влияет на оригинал.

Добавлено позже:
И ещё вопрос N3:
А записать в файл целый класс можно лишь приводя тип к символьному?

--- Код: ---ofstream outCredit("credit.dat", ios::binary);
...
     outCredit.write(reinterpret_cast<const char*> (&blankClient),
                     sizeof(ClientData));
...

--- Конец кода ---
Mr2:

--- Цитата: gepar от 16 Июнь 2011, 14:34:05 ---
--- Код: ---int main()
{
    ifstream file;
    file.open("test.txt", ios::binary);
    if(!file)
     exit(100500);
    char c;
    while(file>>c)
     cout<<c;
    file.close();
    return 0;
}

--- Конец кода ---
Всё равно всё в ряд пишет без пробелов и переводов строк.
--- Конец цитаты ---
Ты все строки загоняешь в одну переменную?
Тогда почему  должны быть пробелы и переводы строк? o_0
Походу работает вот так.

содержимое текстового файла:
один
два
три

while(file>>c)
после ввода в переменную получаем:c="одиндватри";
HoRRoR:

--- Цитата ---Всё равно всё в ряд пишет без пробелов и переводов строк.
--- Конец цитаты ---
Значит специфика ">>". Используй get().


--- Цитата ---Получается при вызове строка.data() создаётся массив указателей с содержимым как у строки (это я выгуглил), но зачем его сделали обязательно const тогда? Всё равно это ведь копия, которая потом никак не влияет на оригинал.
--- Конец цитаты ---
Каких ещё указателей? Создаётся копия строки и даётся на неё указатель, копия действительна до следующего вызова функции. const - потому что это данные объекта класса, принцип инкапсуляции.


--- Цитата ---А записать в файл целый класс можно лишь приводя тип к символьному?
--- Конец цитаты ---
Глупый вопрос. Тип параметра при передаче в функцию должен быть совместим с принимаемым типом. Поэтому, если принимается указатель на char, то должно быть явное преобразование. Если принимался бы указатель на void - можно было бы обойтись без него, т.к. указатель бы сам неявно преобразовался к void*.
gepar:

--- Цитата: Mr2 ---Ты все строки загоняешь в одну переменную?Тогда почему  должны быть пробелы и переводы строк?
--- Конец цитаты ---
А почему их должно не быть когда я поочерёдно считывают содержимое в c ?

--- Цитата: HoRRoR ---Значит специфика ">>". Используй get().
--- Конец цитаты ---
Сменив на while(file.get(c)) теперь выводятся и пробелы с переводами строки.

Добавлено позже:
По поводу режимов открытия файлов:

--- Код: ---fstream outCredit("credit.dat",ios::in|ios::out|ios::binary);

--- Конец кода ---
Чего всюду или было ||, а здесь оно | ? Это же не логично да и вообще было бы логичнее чтобы режимы открытия файлов нужно было перечислять через запятую.
HoRRoR:

--- Цитата ---Чего всюду или было ||, а здесь оно | ? Это же не логично да и вообще было бы логичнее чтобы режимы открытия файлов нужно было перечислять через запятую.
--- Конец цитаты ---
Вот ты читал учебники, столько спрашивал, столько писал, а толку мало - не знаешь даже основ.
| - побитовое "или", || - логическое, то же самое касается & и &&. А с запятой вообще глупо - это в каких-нибудь интерпретируемых языках можно сделать, где не важна ресурсоёмкость и производительность.
gepar:

--- Цитата: HoRRoR ---| - побитовое "или"
--- Конец цитаты ---
Первый раз слышу, ни в курсе с++ универа ни в Дейтеле не было ни слова о таком  :) Единственное что было побитовое так это сдвиг .
gepar:
До конца не понимаю некоторые фичи по работа с файлами. Вот например у Дейтела есть некая программка, я приведу только одну строчку:

--- Код: ---readFromFile.read( reinterpret_cast< char * >( &client ), sizeof( ClientData ) );

--- Конец кода ---
Что мы здесь делаем? Как я понимаю мы считываем в объект client данные из файла readFromFile размера sizeof( ClientData ) байт. А вот что вот это значит уже при чтении данных reinterpret_cast< char * >( &client )? Обратное преобразование из char * в данные типа ClientData ? Данные до этого были преобразованы из ClientData в указатель на char и записаны.
HoRRoR:
ОМГ, тупо читаем данные по адресу client, предварительно приведя указатель к char* без каких-либо проверок (они тут не нужны).
gepar:
HoRRoR,а читаем куда?
Вот полностью одна из функций из примера Дейтела

--- Код: ---// update balance in record
void updateRecord( fstream &updateFile )
{
   // obtain number of account to update
   int accountNumber = getAccount( "Enter account to update" );

   // move file-position pointer to correct record in file
   updateFile.seekg( ( accountNumber - 1 ) * sizeof( ClientData ) );

   // read first record from file
   ClientData client;
   updateFile.read( reinterpret_cast< char * >( &client ),
      sizeof( ClientData ) );

   // update record
   if ( client.getAccountNumber() != 0 )
   {
      outputLine( cout, client ); // display the record

      // request user to specify transaction
      cout << "\nEnter charge (+) or payment (-): ";
      double transaction; // charge or payment
      cin >> transaction;

      // update record balance
      double oldBalance = client.getBalance();
      client.setBalance( oldBalance + transaction );
      outputLine( cout, client ); // display the record

      // move file-position pointer to correct record in file
      updateFile.seekp( ( accountNumber - 1 ) * sizeof( ClientData ) );

      // write updated record over old record in file
      updateFile.write( reinterpret_cast< const char * >( &client ),
         sizeof( ClientData ) );
   } // end if
   else // display error if account does not exist
      cerr << "Account #" << accountNumber
         << " has no information." << endl;
} // end function updateRecord

--- Конец кода ---


Добавлено позже:
Почему после этого

--- Код: ---   updateFile.read( reinterpret_cast< char * >( &client ),
      sizeof( ClientData ) );

--- Конец кода ---
Файл client перестаёт уже быть по умолчанию и в нём появляются данные считанные из файла, мы ведь нигде ему ничего не присваивали.
HoRRoR:

--- Цитата ---HoRRoR,а читаем куда?
--- Конец цитаты ---
Ну ты прикалуешься? Читаем из файла в память по адресу client.
gepar:

--- Цитата: gepar ---Что мы здесь делаем? Как я понимаю мы считываем в объект client данные из файла readFromFile размера sizeof( ClientData ) байт.
--- Конец цитаты ---

--- Цитата: HoRRoR ---ОМГ, тупо читаем данные по адресу client, предварительно приведя указатель к char*
--- Конец цитаты ---

--- Цитата: HoRRoR ---Ну ты прикалуешься? Читаем из файла в память по адресу client.
--- Конец цитаты ---
Это ты мне кажется прикалываешься  :) Ну да теперь точно понятно что оно делает, ато я прошлые выводы делал из наблюдений только. Дейтел только не закончил что-то описывать всё по поводу чтения из файла, он указал что можно как-то хитро полиморфно писать файлы и их идентификаторы (чтобы потом при чтении из файла можно было определить какого именно пользовательского типа этот файл), но не написал как это делать  :( Ну да ладно, дочитаю что там у него дальше по работе со строкам, а потом нагуглю уже на тему сохранения файлов информацию, тем более что у меня осталось куча вопросов прямо сейчас. Например как произвести переименование файла? Первое что можно придумать это создать новый файл с нужным именем и скопировав туда данные из старого удалить старый. Но это подойдёт лишь для вариантов с маленькими файлами, да и не правильно это, HoRRoR,подскажи пожалуйста как последнее реализовать, ато сейчас любопытно  :)
HoRRoR:

--- Цитата ---Это ты мне кажется прикалываешься
--- Конец цитаты ---
Из контекста ясно, что мы читаем их из файла. Никаких обратных преобразований там в помине нет.


--- Цитата ---подскажи пожалуйста как последнее реализовать, ато сейчас любопытно
--- Конец цитаты ---
rename().
gepar:
HoRRoR, а можно как-то понятнее.  Я вижу функция меняет название строк, как же её применить в этом случае:

--- Код: ---int main()
{
    ofstream test("abc.txt", ios::out);
    rename("abc.txt","xyz.txt");
    return 0;
}

--- Конец кода ---
Так ведь как я написал она не работает же. А, я уже понял почему, файл надо закрывать перед переименованием же.


Тот пример что там вообще мне не понятен

--- Код: ---/* rename example */
#include <stdio.h>

int main ()
{
  int result;
  char oldname[] ="oldname.txt";
  char newname[] ="newname.txt";
  result= rename( oldname , newname );
  if ( result == 0 )
    puts ( "File successfully renamed" );
  else
    perror( "Error renaming file" );
  return 0;
}

--- Конец кода ---
В первую очередь мне непонятно почему если у меня нет файла oldname.txt то мне пишет: Error renaming file: No such file or directory. Откуда взялись две точки и строка No such file or directory, их же нету в коде при ошибки чтения файла  :?

Добавлено позже:
Глупо только что эта rename возвращает 1 в случае не удачи, приходиться тогда помнить что возвращает 0 при неудаче, а что 1. Нет чтобы сделать чтобы любая функция возвращала при неудаче 0.

Добавлено позже:
Ну и ещё тогда вопрос: какие функции есть для копирования и удаления файла?  :)

Добавлено позже:
Просто ведь

--- Код: ---    std::ofstream a("abc.txt",std::ios::app);
    std::ofstream b("cde.txt",std::ios::out);
    b=a;

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

Добавлено позже:
Ах да, и ещё вопрос: что уходит на вывод когда мы отправляем файл на печать? какой-то 16ричный адрес я смотрю, но адрес чего это?

Добавлено позже:
И ещё один вопрос (много что-то их у меня сегодня  :blush: ):
какая конструкция является оптимальной когда надо провести цикл с условиями (if) и если условие за весь цикл так ни разу и не выполнилось то тогда выдать сообщение об ошибке (в виде сообщения в cerr например) ? Я делаю по принципу

--- Код: ---bool переменная_для_проверки_выполнения_условия=true;
for()
{
if()
 {
 ...
 bool переменная=false;
 }
}

if (bool переменная)
cerr<<Ошибка

--- Конец кода ---
А есть ли другая какая конструкция более удобная?
gepar:
Немогу разобраться с записью в файл данных созданного класса  :-\
Собственно вот я пишу всё это в файл trans.dat

--- Код: ---int main()
{
    fstream file("trans.dat",ios::in|ios::binary|ios::out);
    if (!file)
    {
        cerr<<"Error";
        return 100500;
    }
    ClientData client1,client2,client3;
    client1.setID(1).setName("Abba").setBalance(2.34);
    client2.setID(2).setName("Baab").setBalance(-2.3);
    cout<<client1<<client2;
    file.write(reinterpret_cast<const char*>(&client1),sizeof(ClientData));
    file.write(reinterpret_cast<const char*>(&client2),sizeof(ClientData));
    file.seekg(0);
    file.read(reinterpret_cast<char*>(&client3),sizeof(ClientData));
    cout<<client3;
}

--- Конец кода ---
По выводу программы (данные client3) видно что запись в файл была успешна и считывание тоже прошло удачно так как в обьекте client3 появились данные считанные из начала файла trans.dat, тоесть были считаны данные такие же как у client1. Файл trans.dat при просмотре через текстовый редактор тоже показывает что данные есть.

Далее я убираю код по записи файла и хочу всего лишь считать данные в client3 и вывести их на печать

--- Код: ---#include <iostream>
#include <fstream>
#include "ClientData.h"
 
using namespace std;
 
int main()
{
    fstream file("trans.dat",ios::in|ios::binary|ios::out);
    if (!file)
    {
        cerr<<"Error";
        return 100500;
    }
    ClientData client1,client2,client3;
//    client1.setID(1).setName("Abba").setBalance(2.34);
//    client2.setID(2).setName("Baab").setBalance(-2.3);
//    cout<<client1<<client2;
//    file.write(reinterpret_cast<const char*>(&client1),sizeof(ClientData));
//    file.write(reinterpret_cast<const char*>(&client2),sizeof(ClientData));
    file.seekg(0);
    file.read(reinterpret_cast<char*>(&client3),sizeof(ClientData));
    cout<<client3;
}

--- Конец кода ---
И я тут же получаю ошибку, второй день матерюсь и не могу понять где я совершаю ошибку при чтении файла. Что я не так делаю подскажите пожалуйста. В прикреплённом файле помимо этого main и код самого класса ClientData.

Добавлено позже:
Пробовал открывать второй раз файл только для чтения - получал ту же ошибку так что не знаю где я накосячил или может что не правильно понял по считыванию данных, собственно из-за этого же не могу сделать в другой программе нормальное чтение и распечатку данных из файла.
gepar:
Проблема с классом ClientData решена, не надо было строку использовать для хранения данных, теперь работает когда сделал символьный массив. Тем не менее почему так? sizeof возвращает ведь тот же размер что для пустрой строки, что для строки с данными ... правда sizeof то делает это на этапе компиляции. В общем надо отказаться от использования строк в классах, данные которые планируется сохранять в бинарный файл с возможностью мгновенного доступа к любой записи из файла.
gepar:
Не могу разобраться с записью объекта созданного мною класса в файл, видать мой класс для этого до конца не подходит (с каждым запуском скомпилированной версии программы пишутся в файл разные символы, точнее первый символ тот же, а остальные - меняются каждый раз ). У меня у моего класса есть 3 поля данных: номер, имя и баланс, так вот номер я так понимаю сейвит в файл оно нормально (вот это и есть тот первый символ при просмотре текстовым редактором что не меняется), а вот имя и баланс перекручиваются почему-то. Помогите добиться полной статичности класса чтобы каждый раз при его записи данные при просмотре текстовым редактором были одинаковые, ато когда оно каждый раз по новому получается то я потом дальше не могу считать данные корректно.

ClientData.h (Заголовочный файл к классу)

--- Код: ---#ifndef CLIENTDATA_H
#define CLIENTDATA_H

#include <string>
using std::string;


class ClientData
{
public:
    //конструктор по умолчанию который устанавливает
    //номер =0, имя = пустой строке и баланс =0
    ClientData(int=0,string="",double=0.0);

    void setID(int);
    int getID() const;

    void setName(string);
    string getName() const;

    void setBalance(double);
    double getBalance() const;


private:
    int ID; //номер
    char name[15]; //имя
    double balance; // баланс
};

#endif

--- Конец кода ---

ClientData.cpp (реализация самого класса)

--- Код: ---#include <string>
using std::string;

#include <cstring>
#include "ClientData.h"

ClientData::ClientData(int i, string n, double b)
{
    setID(i);
    setName(n);
    setBalance(b);
}

void ClientData:: setID(int i)
{
    ID=i;
}

int ClientData:: getID() const
{
    return ID;
}

void ClientData:: setName(string n)
{
    const char* lname=n.data();
    int length=n.size();
    length=(length<15 ? length : 14);
    strncpy(name,lname,length);
    name[length]='\0';
}

string ClientData:: getName() const
{
    string ret(name);
    return ret;
}

void ClientData:: setBalance(double b)
{
    balance=b;
}

double ClientData:: getBalance() const
{
    return balance;
}

--- Конец кода ---

main(совершаю только запись в файл 10 объектов типа ClientData

--- Код: ---#include <iostream>
#include <iomanip>
#include <fstream>
#include "ClientData.h"
using namespace std;
 
void newRecord(fstream&);
int menu();
void print(fstream&);
void print2(fstream&);
 
int main()
{
    //создаю объект типа ClientData
    ClientData client;
   
    //открываю файл для чтения и записи в бинарном режиме
    fstream file("trans.dat",ios::binary|ios::in|ios::out);
    if (!file)
     cerr<<"Error";
 
    //записываю 10 моих объектов в файл
    for (int i=0;i<10;i++)
     file.write(reinterpret_cast<const char*>(&client),sizeof(ClientData));
}

--- Конец кода ---
Пробовал писать на программерских форумах - что-то не могут они подсказать в этом вопросе ...
gepar:
Продолжаю изучать с++, некоторые вещи в с++ вовсе нелогичные и работают через задницу (хотя по сути это отсалось от си). Вот как можно было додуматься сделать так чтобы стандартная функция toupper для конвертации букв в ВЕРХНИЙ РЕГИСТР возвращала код символа в  виде числа int, ну это же вообще не логично, ну ни капельки же.
HoRRoR:
Функция принимает и возвращает код символа, почему он должен быть именно в char?
gepar:
HoRRoR,ну разве сложно было выбрать возвращаемый тип char, какраз бы обратная конвертация из int и пошла бы и вернулся бы готовый символ, а так приходится при её использовании использовать ещё конвертацию в char.
А вообще я тут переписывал некоторые стандартные функции и на одном шаге столкнулся с непонятной мне проблемой:

--- Код: ---void *memmove(void *s1, const void *s2, size_t n)
{
    char *s11=(char*)s1;
    char *temp=new char [n+1];
    char *s22=(char*)s2;
    strncpy(temp,s22,n);
    //cout<<"TEST: "<<temp<<endl;
 
    //здесь в цикле почему-то убирается по  первому символу за цикл
    //у каждой переменной, те у temp убирается "abc", а у s11 "sim".
    // почему так? Я же хотел только скопировать "abc" в строку s11
    // вместо sim
    for (size_t i=0;i<n;i++)
    {
        *(s11++)=*(temp++);
 
    }
    return s11;
}

--- Конец кода ---
Я то потом банально использовал предыдущую свою функцию для копирования

--- Код: ---void *memcpy(void *s1, const void *s2, size_t n)
{
    char *s11=(char*)s1;
    char *s22=(char*)s2;
    for (size_t i=0;i<n;i++)
    {
        *s11++=*s22++;
    }
    return s11;
}

void *memmove(void *s1, const void *s2, size_t n)
{
    char *s11=(char*)s1;
    char *temp=new char [n+1];
    char *s22=(char*)s2;
    memcpy(temp,s22,n);
    memcpy(s11,temp,n);
    return s11;
}

--- Конец кода ---
Но мне всё равно интересно откуда брался в предыдущей реализации "сдвиг", может кто знает?
Навигация
Главная страница сообщений
Следующая страница
Предыдущая страница

Перейти к полной версии