Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа со строками, байтами, битами и т.п.  (Прочитано 12180 раз)
0 Пользователей и 1 Гость смотрят эту тему.
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« : 02-10-2005 10:24 » 

Рад всех приветствовать.
Вопрос номер раз:
делаю так
Код:
ifstream in("decodefile.txt");
if(!in)
{
cout << "Error of file open";
return 1;
}
char str[120];                     
                       while(in)
{
                        in >> str;
                        cout <<str;

}
Происходит считывание до первого пробела. А мне нужно чтобы считывалась целая строка, а еще лучше, чтобы считывалось нужное мне количество байт. Как это дело организовать?

Вопрос номер два:
 Потом мне то, что содержится в str[] нужно загонять в тип unsigned int (т.е. в переменные этого типа). Вот как я делаю:
Код:
unsigned int *str_int;
str_int=(unsigned int*)str;
Здесь по сути бегает указатель типа unsigned int по массиву типа char. Сделав так:
Код:
unsigned int A,B;
A=*str_int;
B=*(str_int++);
Я буду добиваться того, что мне надо. Я прав?? Вроде как мне кажется да, но на практике что-то не то.
Код:
         ifstream in("1.txt");
         unsigned int A,B;
         char str[120];
         unsigned int *str_int;   
                       while(in)
{ in >> str;
                        cout <<str<<"---";
str_int=(unsigned int *)str;
cout <<*str_int<<"---"<< hex<<*str_int<<"\n";
}
            A=*str_int;
B=*(str_int-1);
    in.close();
   cout <<A<<"---"<<B;
Вот файл, который я считываю
Цитата
dkkaa222h111h444c1122fffc111222333
А вот что выводится
Цитата
dkkaa222h111h444c1122fffc111222333---1634429796---616b6b64
---616b6b00---616b6b00
616b6b00---12fdc0
Невооруженным глазом видно, что переменная В не содержит в себе предыдущие 4 байта.
Я пробовал B=*(str_int+1);
Тогда вот что получается
Цитата
dkkaa222h111h444c1122fffc111222333---1634429796---616b6b64
---616b6b00---616b6b00
616b6b00---32323261
Как видно в В опять содержится что-то другое.
Что не так?
Записан

ещё один вопрос ...
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 02-10-2005 15:19 » 

Вопрос номер раз:
...
Происходит считывание до первого пробела. А мне нужно чтобы считывалась целая строка, а еще лучше, чтобы считывалось нужное мне количество байт. Как это дело организовать?

У istream/ostream  есть операции read/write, которые принимают в качестве аргумет\нтов указатель на буфер и кол-во байт для  чтения/записи. ifstream наследуется от istream, значит работет и для него.
Выглядит примерно так:

int bytes_to_read = 10;
in.read(str, bytes_to_read);

Только чтобы все корректно работало, неплохо бы было при открытии файла указать, что он бинарный:

ifstream in("decodefile.txt", ios::binary);

а то иногда траблы бывают. Но если всегда работаешь с текстовыми файлами, то можно и не указывать.
Записан
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 02-10-2005 18:27 » 

Вопрос номер два:
 Потом мне то, что содержится в str[] нужно загонять в тип unsigned int (т.е. в переменные этого типа). Вот как я делаю:
...
Я пробовал B=*(str_int+1);
Тогда вот что получается
Цитата
dkkaa222h111h444c1122fffc111222333---1634429796---616b6b64
---616b6b00---616b6b00
616b6b00---32323261
Как видно в В опять содержится что-то другое.

Ты не сказал, какие значения ты ожидал увидеть?

1. Давай посмотрим на твой считанный буфер в шестнадцатеричном виде:

64 6b 6b 61 61 32 32 32 68 31 31 31 68 34 34 34 ...
d  k  k  a  a  2  2  2  h  1  1  1  h  4  4  4 ...

Указатель str_int установлен на начало этого буфера.
При выполнении
Код:
A = *str_int;
переменная А будет содержать значение, состоящее из байтов буфера (0 .. 3), а именно 0x616b6b64.
Далее ты выполняешь
Код:
B = *(str_int + 1);
Что здесь происходит? В на 32-разрядных платформах  размер unsigned int равен 4 байтам. Ты смещаешь указатель на 1 int (или на 4 байта) и пытаешься получить значение unsigned int располеженное в байтах буфера (4 .. 7). После этого переменная В будет содержать значение 0x32323261.

Из приведенной цитаты видно, что именно это значение ты и получаешь - самое последнее в выводе на экран:
Цитата
dkkaa222h111h444c1122fffc111222333---1634429796---616b6b64
---616b6b00---616b6b00
616b6b00---32323261

Так что вариант с (str_int +1)  является единственно правильным.

Если же выполнить str_int - 1, то указатель сместится на адрес памяти, который не имеет никакого отношения к буферу - на 4 байта раньше начала твоего буфера. Поэтому неудивителльно, что в этом случае ты получаешь непредсказуемый мусор 12fdc0:
Цитата
...
616b6b00---12fdc0

2. Теперь по поводу строки "---616b6b00---616b6b00" и странного значения переменной А: 0x616b6b00.
У ifstream'ов есть "нехорошее" свойство - при достижении конца файла они не сразу возвращают eof, а разрешают еще одно считывание из файла, причем это считывание будет неправильным.
Поэтому правильно считывать как-нибудь так:
Код:
while(!in.eof())
{
    in >> str;
    if (in.good())
    {
        cout <<str<<"---";
        str_int=(unsigned int *)str;
        cout <<*str_int<<"---"<< hex<<*str_int<<"\n";
    }
}
A=*str_int;
B=*(str_int+1);
in.close();
cout << "A = " <<A<<"--- B = "<<B;
В этом случае выдод на экран будет выглядеть так:
Цитата
dkkaa222h111h444c1122fffc111222333---1634429796---616b6b64
A = 616b6b64--- B = 32323261
Тут все верно.
« Последнее редактирование: 20-12-2007 17:54 от Алексей1153++ » Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 03-10-2005 18:03 » 

Если я не ошибаюсь, то read|write - это функции для бесформатного ввода/ывода. Я знаю что разница между текстовым и бесформатным вводом выводом заключается в реакции на символы пробелов, знаков табуляции. Но я так и не понял суть этой реакции. в каком случае преобразуются пробелы в каком нет. Но совет Hooter'a был кстати (за что большое при большое СПАСИБО). Потому как эффект меня утсраивает и пока решил юзать get(), которая во многом сродни read(), только посимвольная.
Цитата
Теперь по поводу строки "---616b6b00---616b6b00" и странного значения переменной А: 0x616b6b00.
У ifstream'ов есть "нехорошее" свойство - при достижении конца файла они не сразу возвращают eof, а разрешают еще одно считывание из файла, причем это считывание будет неправильным.
За это еще раз спасибо, потому как об этом я нигде не читал и долго бы еще мог бы врубаться в эти чудеса.
Я там еще напутал с битами и их порядком, тупил нещадно Жаль
« Последнее редактирование: 20-12-2007 17:56 от Алексей1153++ » Записан

ещё один вопрос ...
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 03-10-2005 20:54 » 

Как произвести сброс указателя чтения. Т.е. файл был прочитан до конца и необходимо его прочитать еще раз сначала, что для этого нужно?
Пробовал функцию seekg() c различными вариациями параметров, но что-то эффекта нет.
Вот вариации:
in.seekg(0);
in.seekg(ios:beg);
in.seekg(0,ios::beg);
in.seekg((ios::beg)+1);
in.seekg();
//то же самое так
ios::seekg   
 
но так и не достиг я ожидаемого эффекта
while(in.get(temp))
cout<<temp;
Хотя если эти операции проделать самый первый раз, то содержимое файла выводится.
Сбрасывать указатель пробовал так:
in.close();
in.open("decodefile.txt",ios::binary);
Тоже не помогло. Что не так?
Записан

ещё один вопрос ...
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 04-10-2005 04:26 » 

Вроде бы seekg(0, ios::beg) должно работать.
И в MSDN, и у страуструпа, и в стандарте - написано именно так.

В msdn есть пример, попробуй его собрать и запустить.

Попробуй вызвать другие методы класса, например, tellg - если проблемы с состоянием класса, то он тоже будет ошибку выдавать.
Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 04-10-2005 16:08 » 

Делаю вот так:
Код:
unsigned int A, B, C, D;
unsigned int *s;
unsigned int *str_int=NULL;
char *str, temp;
  s=new unsigned int[2*r+3];
  str=new char[w/8];
////////////////////////
  ifstream in("decodefile.txt",ios::binary);
ofstream out("out.txt");
if(!in)
{
cout << "Error of file open";
return 1;
}
    //-----------------------------------             
                                 
                     
           while(!in.eof())
               
   {
            if(in.good())
{
   in.read(str,w/8);
   str_int=(unsigned int*)str;
   A=*str_int;
   in.read(str,w/8);
   str_int=(unsigned int*)str;
   B=*str_int;
   in.read(str,w/8);
   str_int=(unsigned int*)str;
   C=*str_int;
   in.read(str,w/8);
   str_int=(unsigned int*)str;
   D=*str_int;
   cout <<A<<"|"<<B<<"|"<<C<<"|"<<D<<"\n" ;
  }
   }
   cout<<"\n\n------------------\n\n";
   
   in.seekg(0,ios::beg);
   cout <<in.tellg();
          while(in.get(temp))
cout<<temp;
   in.close();
   out.close();
   
   
return 0;
}
tellg возращает -1, почему-то. Я уже задолбался р=пальцем в небо тыкать, такое ущущение, что это я туплю в какой-нибудь мелоче.
Записан

ещё один вопрос ...
Hooter
Опытный

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 04-10-2005 20:04 » 

В твоем коде есть некоторый недочет.

Дело в том, что для потоков вызов методов good(), bad() и fail() имеет смысл только после вызова операций, меняющих состояние класса потока. Например, read, write, operator>>, operator<< - меняют его состояние. Поэтому твой код надо модифицировать так, чтобы вызов good() происходил каждый раз после вызова read(). Например, так:
Код:
while(!in.eof())
{
   in.read(str,w/8);
   if (!in.good())
      continue; // или break
   str_int=(unsigned int*)str;
   A=*str_int;

   in.read(str,w/8);
   if (!in.good())
      continue;
   str_int=(unsigned int*)str;
   B=*str_int;

   in.read(str,w/8);
   if (!in.good())
      continue;
   str_int=(unsigned int*)str;
   C=*str_int;

   in.read(str,w/8);
   if (!in.good())
      continue;
   str_int=(unsigned int*)str;
   D=*str_int;

   cout <<A<<"|"<<B<<"|"<<C<<"|"<<D<<"\n" ;
}

То есть мы проверяем, корректно ли прошла операция считывания из файла. В нашем случае, операция read может пройти некорректно, когда достигнут конец файла.

tellg возращает -1, почему-то. Я уже задолбался р=пальцем в небо тыкать, такое ущущение, что это я туплю в какой-нибудь мелоче.

То, что tellg возвращает -1 говорит только об одном: класс потока вошел в состояние fail. Это ты можешь проверить, вызвав in.fail() - должен вернуть true. Так как поток находится в состоянии fail, то seekg тоже не будет работать. Об этом написано в документации.

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

Очистить состояние класса потока от ошибок можно с помощью метода clear().

Код:
in.clear();
in.seekg(0,ios::beg);
cout <<in.tellg();

Если in.fail() возвращает false, то seekg и tellg будут работать. То есть, если конец файла не достигнут - clear() можно не вызывать.
« Последнее редактирование: 04-10-2005 20:07 от Hooter » Записан
nikedeforest
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 05-10-2005 11:47 » new

То что надо. Спасибо.
Записан

ещё один вопрос ...
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines