Страницы

Поиск по вопросам

Показаны сообщения с ярлыком вывод. Показать все сообщения
Показаны сообщения с ярлыком вывод. Показать все сообщения

четверг, 2 января 2020 г.

На С++ при выводе строки стринг в файл, записывает крякозябры

#cpp #файлы #строки #вывод


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

#include 
#include 
#include 
#include 
#include 

using namespace std;

int dlina(){
    char *str = new char [1024];
    int i=0;
    ifstream base("1.txt");
    while (!base.eof())
    {
        base.getline(str, 1024, '\n');
        i++;
    }
    base.close();
    delete str;
    return i;

}

int main() {
    string a;
    string b;

    ifstream fin("2.txt");

    FILE *f;
    f= fopen("2.txt", "a+");
        cin>> a;

    int len,len1;

    len1=a.length();
    len=dlina();

    bool l=false;   

    for (int i=0; i>b; 

        if(a==b) l=true;
    }

    if(l==false) {
    fwrite(&a,sizeof(string),1,f);
    }
    fin.close();
    //fclose(f);
    return 0;

}

    


Ответы

Ответ 1



записывать с++ строки с помощью с функций вот таким способом fwrite(&a,sizeof(string),1,f); нельзя. Будет писаться совсем не то, что Вы ожидаете. Даже банальная логика подсказывает, что 'sizeof(string)' не зависит от данных, которые находятся в строке. Если Вам нужно записать именно std::string в файл таким способом, делайте так fwrite(a.c_str(),(a.length()+1),1,f); P.S. если пишите на с++, то лучше использовать функции с++.

пятница, 27 декабря 2019 г.

Ввод/вывод в консоли, C++

#cpp #visual_studio_2015 #консоль #вывод #ввод


Здравствуйте.

Решил написать небольшую RPG-игру с псевдографикой в консоли. 
Для считывания нажатий клавиш использовал функцию GetAsyncKeyState из Windows.h

bool isKeyPressed(int virtualKeyCode)
{
    short keyState = GetAsyncKeyState(virtualKeyCode);
    return ((keyState & 0x8000) > 0);
}


В функции Update проверяю состояние клавиш и изменяю направления движения героя.

 void Update()
    {
    if(_kbhit())
    {   if (isKeyPressed('W'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(0, -1);
            moveUnitTo(&unitsArr[heroIndex]);
        }
        else if (isKeyPressed('S'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(0, 1);
            moveUnitTo(&unitsArr[heroIndex]);

        }
        else if (isKeyPressed('A'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(-1, 0);
            moveUnitTo(&unitsArr[heroIndex]);

        }
        else if (isKeyPressed('D'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(1, 0);
            moveUnitTo(&unitsArr[heroIndex]);
        }
    ...
    }


После этого захотел написать функцию, которая выводила бы на экран вопрос, и при
помощи _getch() считывала бы ответ игрока (y/n)

bool getAnswerFromLogPanel(const string questionMessage)
{
    UpdateLog(questionMessage + " [Y]/[N]");

    const char inputAnswer = tolower(_getch());
    if (inputAnswer == 'y')
    {
        UpdateLog("[Y]");
        return true;
    }

    UpdateLog("[N]");
    return false;
}


Здесь столкнулся с проблемой, что _getch() не останавливает поток и не ждет нажатия
клавиши.

При этом если использовать вместо _getch() функцию getchar() или cin.get() на экран
консоли выводятся символы ранее нажатых клавиш.





Как я понял,_getch() просто считывает один символ из последних нажатых клавиш (те,
которые выводит на экран getchar() или cin.get()) и поэтому не останавливает поток.

То что мне не помогло:

cin.ignore(), cin.clear(), cin.sync(), system("cls"), fflush(stdin).

То что работает, но не так как надо:


Работает, но если до этого когда-то была нажата клавиша Y или N - ответ будет считываться
с нее.

do
{
    char input = _getch();
    input = tolower(input);

    if (input == 'y')
   {
       UpdateLog("[Y]");
       return true;
   }

    if(input == 'n')
    {
        UpdateLog("[N]");
        return false;
    }
} while (true);

При каждом срабатывании _kbhit() считывать при помощи _getch() символ с потока.
Но тогда движение героя и реакция на нажатия клавиш значительно замедляется.


C++, Visual Studio 2015
    


Ответы

Ответ 1



Поскольку потоковое чтение работает в конечном итоге через WinAPI-шные функции и не ожидает, что будет использован прямой доступ к тем же функциям, то оно не дружит с низкоуровневым вводом через GetAsyncKeyState. Поэтому, если уж вы пользуетесь низкоуровневыми функциями, пользуйтесь ими всё время. Для вашего случая, вам должны помочь FlushConsoleInputBuffer (чтобы сбросить буферизацию уже нажатых к текущему моменту клавиш) и ReadConsoleInput. Вот общая страница документации, на всякий случай.

четверг, 19 декабря 2019 г.

Лишний байт при записи структуры в файл

#cpp #c #файлы #вывод #запись


Откуда берется лишний байт?

#include 
#include 
#include 

#pragma pack(push, 1)
typedef struct {
    int a;
    float b;
} structEx;
#pragma pack(pop)
using namespace std;
int main()
{
    {
        structEx x;
        x.a = 2;
        x.b = 4.2;
        ofstream fout("Text1.txt");
        for (int i = 0; i < 10; i++) {
            x.a += 3;
            x.b += 0.5;
            fout.write((char *)&x, sizeof(x));
        }
        fout.close();
    }
    {
        structEx x;
        x.a = 2;
        x.b = 4.2;
        ofstream fout("Text2.txt");
        for (int i = 0; i < 10; i++) {
            x.a += 3;
            x.b += 0.51;
            fout.write((char *)&x, sizeof(x));
        }
        fout.close();
    }
    return 0;
}


Text1.txt при x.b += 0.5;

// 0500 0000 6666 9640 0800 0000 6666 a640
// 0b00 0000 6666 b640 0e00 0000 6666 c640
// 1100 0000 6666 d640 1400 0000 6666 e640
// 1700 0000 6666 f640 1a00 0000 3333 0341
// 1d00 0000 3333 0b41 2000 0000 3333 1341


Text2.txt при x.b += 0.51;

// 0500 0000 52b8 9640 0800 0000 3e0d 0aa7
// 400b 0000 002a 5cb7 400e 0000 0016 aec7
// 4011 0000 0002 00d8 4014 0000 00ee 51e8
// 4017 0000 00da a3f8 401a 0000 00e3 7a04
// 411d 0000 00d9 a30c 4120 0000 00cf cc14
// 41

    


Ответы

Ответ 1



По умолчанию потоки открываются в текстовом режиме (при котором символ \n преобразуется в Windows в пару \r\n), так что надо просто вместо ofstream fout("Text.txt"); написать ofstream fout("Text.txt", ios::binary); Компьютер не понимает разницы между бинарными и текстовыми данными - для него все это один поток байтов, а что они означают - ему безразлично. Когда вы открываете файл для записи в текстовом режиме в соответствующей операционной системе, это означает команду "пиши байты как есть, но если встретишь байт 0x0A - запиши пару 0x0D 0x0A". А при чтении - наоборот - "если встретишь эту пару байт - то в память заноси только один 0x0A".

Ответ 2



Под операционной системой Linux данный код выполняется корректно и не производит добавление лишних байт в файл. root@debian:/# g++ 1.cpp root@debian:/# ./a.out root@debian:/# hexdump -C Text1.txt 00000000 05 00 00 00 66 66 96 40 08 00 00 00 66 66 a6 40 |....ff.@....ff.@| 00000010 0b 00 00 00 66 66 b6 40 0e 00 00 00 66 66 c6 40 |....ff.@....ff.@| 00000020 11 00 00 00 66 66 d6 40 14 00 00 00 66 66 e6 40 |....ff.@....ff.@| 00000030 17 00 00 00 66 66 f6 40 1a 00 00 00 33 33 03 41 |....ff.@....33.A| 00000040 1d 00 00 00 33 33 0b 41 20 00 00 00 33 33 13 41 |....33.A ...33.A| 00000050 root@debian:/# hexdump -C Text2.txt 00000000 05 00 00 00 52 b8 96 40 08 00 00 00 3e 0a a7 40 |....R..@....>..@| 00000010 0b 00 00 00 2a 5c b7 40 0e 00 00 00 16 ae c7 40 |....*\.@.......@| 00000020 11 00 00 00 02 00 d8 40 14 00 00 00 ee 51 e8 40 |.......@.....Q.@| 00000030 17 00 00 00 da a3 f8 40 1a 00 00 00 e3 7a 04 41 |.......@.....z.A| 00000040 1d 00 00 00 d9 a3 0c 41 20 00 00 00 cf cc 14 41 |.......A ......A| 00000050 Как уже ответили, проблема происходит под некоторыми устаревшими операционными системами, сам же код ошибки не содержит. Не ищите ошибку там, где ее нет.

среда, 27 ноября 2019 г.

Вывод числа double (10^18)+1

#double #c #вывод #c++


Увидев этот код
#include 
#include 
using namespace std;
int main()
{
    double d = 1000000000000000001;
    cout.setf(ios::fixed);
    cout.precision(0); //0 - число символов после точки
    cout << d << endl;
    printf("%.0lf\n",d);
    return 0;
}

Неожиданно увидел в результате (http://ideone.com/1SEHpO)

1000000000000000000
1000000000000000000


Куда делась 1?
Из за чего так происходит? Особенности записи типов с плавающей точкой?    


Ответы

Ответ 1



У типа double ограниченная точность, поэтому в нём невозможно различить 1000000000000000000 и 1000000000000000001. Если вы объявите double d1 = 1000000000000000001; double d2 = 1000000000000000000; — то d1 и d2 будут одним и тем же числом. Пруф: http://ideone.com/WqQSAd Проблема в том, что числа с плавающей точкой не бесконечно точны. Для типа double, например, выделяется 52 бита под значащие цифры (и ещё 11 бит под показатель степени), число внутри хранится как бы закодированным в виде CCCCCCC * 2^PPPP (C — значащие цифры, P — степень). А значит, числа, которые можно представить в виде double, расположены с некоторым шагом (который зависит от величины порядка): числа, расположенные «между» представимыми числами выразить точно с помощью double вообще нельзя, и они автоматически округляются до ближайшего представимого числа. Пример такого числа — 0.1: оно не выражается (двоичной) дробью, и константа 0.1 внутри хранится как приблизительно 0.1000000000000000055511151231257827021181583404541015625 Максимальное значение, которое можно прибавить к единице так, чтобы она не изменилась, называется машинным эпсилоном. Для типа double машинный эпсилон равен, очевидно, 2⁻⁵³, то есть около 1.11e-16. Почему очевидно? Потому что для единицы значащие биты такие: 10000000...000, а значит, следующее по величине число, которое можно выразить типом double, должно иметь значащие цифры 10000000...001. (На самом деле чуть-чуть сложнее: ведущая единица не хранится, а подразумевается.) Отсюда выплывает, что 1 + 1e-16 для типа double неотличимо от 1. Поскольку для бóльших чисел увеличивается порядок, при увеличении первого слагаемого машинный эпсилон приблизительно пропорционально увеличивается. Соответственно, 1e16 + 1 будет равно 1e16. В вашем же случае вы на два порядка выше предела: вы прибавляете к 1e18. Давайте ещё проэкспериментируем: http://ideone.com/4XJxFj 1 + 1.110223024625156e-16 == 1 но уже 1 + 1.110223024625157e-16 != 1 Это потому, что 1.110223024625156e-16 — приближение к 2⁻⁵³. Ещё немного информации о числах с плавающей точкой: Хорошая статья на Хабре Классическая статья с теоретическими выкладками, но на английском. Если вам нужно представлять числа с высокой точностью, даже типа long double может не хватить. В этом случае, возможно, придётся применять числа бесконечной точности. Такие числа являются встроенными в некоторых языках (например, Java и C#), а для C и C++ есть хорошие библиотеки, предоставляющие такие числа. Я бы порекомендовал GMP.

четверг, 11 июля 2019 г.

PHP вывод даты с буквенным месяцем

Чем можно заменить следующий код
switch (substr($bill['from'], 5, 2)) { case '01': { $str_from = substr($bill['from'], 3, 2). ' января '.substr($bill['from'], 0, 4); } break; case '02': { $str_from = substr($bill['from'], 3, 2). ' февраля '.substr($bill['from'], 0, 4); } break; ....... case '12': { $str_from = substr($bill['from'], 3, 2). ' декабря '.substr($bill['from'], 0, 4); } break; }
$bill['from']='2015-08-15 15:15:15'; //свитч echo $str; //вывод: "15 августа 2015"


Ответ

$bill['from']='2015-08-15 15:15:15'; $date = strtotime($bill['from']); $month_names = array(1 => 'января', 2 => 'февраля', 3 => 'марта', 4 => 'апреля', 5 => 'мая', 6 => 'июня', 7 => 'июля', 8 => 'августа', 9 => 'сентября', 10 => 'октября', 11 => 'ноября', 12 => 'декабря'); $month_name = $month_names[date('n', $date)]; $str_from = date("d ", $date).$month_name.date(" Y", $date);
15 августа 2015

понедельник, 3 декабря 2018 г.

Ввод/вывод в консоли, C++

Здравствуйте.
Решил написать небольшую RPG-игру с псевдографикой в консоли. Для считывания нажатий клавиш использовал функцию GetAsyncKeyState из Windows.h
bool isKeyPressed(int virtualKeyCode) { short keyState = GetAsyncKeyState(virtualKeyCode); return ((keyState & 0x8000) > 0); }
В функции Update проверяю состояние клавиш и изменяю направления движения героя.
void Update() { if(_kbhit()) { if (isKeyPressed('W')) { unitsArr[heroIndex].changeMoveDirectionTo(0, -1); moveUnitTo(&unitsArr[heroIndex]); } else if (isKeyPressed('S')) { unitsArr[heroIndex].changeMoveDirectionTo(0, 1); moveUnitTo(&unitsArr[heroIndex]);
} else if (isKeyPressed('A')) { unitsArr[heroIndex].changeMoveDirectionTo(-1, 0); moveUnitTo(&unitsArr[heroIndex]);
} else if (isKeyPressed('D')) { unitsArr[heroIndex].changeMoveDirectionTo(1, 0); moveUnitTo(&unitsArr[heroIndex]); } ... }
После этого захотел написать функцию, которая выводила бы на экран вопрос, и при помощи _getch() считывала бы ответ игрока (y/n)
bool getAnswerFromLogPanel(const string questionMessage) { UpdateLog(questionMessage + " [Y]/[N]");
const char inputAnswer = tolower(_getch()); if (inputAnswer == 'y') { UpdateLog("[Y]"); return true; }
UpdateLog("[N]"); return false; }
Здесь столкнулся с проблемой, что _getch() не останавливает поток и не ждет нажатия клавиши.
При этом если использовать вместо _getch() функцию getchar() или cin.get() на экран консоли выводятся символы ранее нажатых клавиш.


Как я понял,_getch() просто считывает один символ из последних нажатых клавиш (те, которые выводит на экран getchar() или cin.get()) и поэтому не останавливает поток.
То что мне не помогло:
cin.ignore(), cin.clear(), cin.sync(), system("cls"), fflush(stdin)
То что работает, но не так как надо:
Работает, но если до этого когда-то была нажата клавиша Y или N - ответ будет считываться с нее.
do { char input = _getch(); input = tolower(input);
if (input == 'y') { UpdateLog("[Y]"); return true; }
if(input == 'n') { UpdateLog("[N]"); return false; } } while (true); При каждом срабатывании _kbhit() считывать при помощи _getch() символ с потока. Но тогда движение героя и реакция на нажатия клавиш значительно замедляется.
C++, Visual Studio 2015


Ответ

Поскольку потоковое чтение работает в конечном итоге через WinAPI-шные функции и не ожидает, что будет использован прямой доступ к тем же функциям, то оно не дружит с низкоуровневым вводом через GetAsyncKeyState
Поэтому, если уж вы пользуетесь низкоуровневыми функциями, пользуйтесь ими всё время.
Для вашего случая, вам должны помочь FlushConsoleInputBuffer (чтобы сбросить буферизацию уже нажатых к текущему моменту клавиш) и ReadConsoleInput. Вот общая страница документации, на всякий случай.

вторник, 30 октября 2018 г.

Лишний байт при записи структуры в файл

Откуда берется лишний байт?
#include #include #include
#pragma pack(push, 1) typedef struct { int a; float b; } structEx; #pragma pack(pop) using namespace std; int main() { { structEx x; x.a = 2; x.b = 4.2; ofstream fout("Text1.txt"); for (int i = 0; i < 10; i++) { x.a += 3; x.b += 0.5; fout.write((char *)&x, sizeof(x)); } fout.close(); } { structEx x; x.a = 2; x.b = 4.2; ofstream fout("Text2.txt"); for (int i = 0; i < 10; i++) { x.a += 3; x.b += 0.51; fout.write((char *)&x, sizeof(x)); } fout.close(); } return 0; }
Text1.txt при x.b += 0.5;
// 0500 0000 6666 9640 0800 0000 6666 a640 // 0b00 0000 6666 b640 0e00 0000 6666 c640 // 1100 0000 6666 d640 1400 0000 6666 e640 // 1700 0000 6666 f640 1a00 0000 3333 0341 // 1d00 0000 3333 0b41 2000 0000 3333 1341
Text2.txt при x.b += 0.51;
// 0500 0000 52b8 9640 0800 0000 3e0d 0aa7 // 400b 0000 002a 5cb7 400e 0000 0016 aec7 // 4011 0000 0002 00d8 4014 0000 00ee 51e8 // 4017 0000 00da a3f8 401a 0000 00e3 7a04 // 411d 0000 00d9 a30c 4120 0000 00cf cc14 // 41


Ответ

По умолчанию потоки открываются в текстовом режиме (при котором символ
преобразуется в Windows в пару
), так что надо просто вместо
ofstream fout("Text.txt");
написать
ofstream fout("Text.txt", ios::binary);
Компьютер не понимает разницы между бинарными и текстовыми данными - для него все это один поток байтов, а что они означают - ему безразлично. Когда вы открываете файл для записи в текстовом режиме в соответствующей операционной системе, это означает команду "пиши байты как есть, но если встретишь байт 0x0A - запиши пару 0x0D 0x0A". А при чтении - наоборот - "если встретишь эту пару байт - то в память заноси только один 0x0A"

четверг, 4 октября 2018 г.

Вывод числа double (10^18)+1

Увидев этот код #include #include using namespace std; int main() { double d = 1000000000000000001; cout.setf(ios::fixed); cout.precision(0); //0 - число символов после точки cout << d << endl; printf("%.0lf
",d); return 0; } Неожиданно увидел в результате (http://ideone.com/1SEHpO) 1000000000000000000 1000000000000000000 Куда делась 1? Из за чего так происходит? Особенности записи типов с плавающей точкой?


Ответ

У типа double ограниченная точность, поэтому в нём невозможно различить 1000000000000000000 и 1000000000000000001. Если вы объявите double d1 = 1000000000000000001; double d2 = 1000000000000000000; -- то d1 и d2 будут одним и тем же числом. Пруф: http://ideone.com/WqQSAd Проблема в том, что числа с плавающей точкой не бесконечно точны. Для типа double, например, выделяется 52 бита под значащие цифры (и ещё 11 бит под показатель степени), число внутри хранится как бы закодированным в виде CCCCCCC * 2^PPPP (C -- значащие цифры, P -- степень). А значит, числа, которые можно представить в виде double, расположены с некоторым шагом (который зависит от величины порядка): числа, расположенные "между" представимыми числами выразить точно с помощью double вообще нельзя, и они автоматически округляются до ближайшего представимого числа. Пример такого числа: 0.1: оно не выражается (двоичной) дробью, и константа 0.1 внутри хранится как приблизительно 0.1000000000000000055511151231257827021181583404541015625 Максимальное значение, которое можно прибавить к единице так, чтобы она не изменилась, называется машинным эпсилоном. Для типа double машинный эпсилон равен, очевидно, 2^-53, то есть около 1.11e-16 Почему очевидно? Потому что для единицы значащие биты такие: 10000000...000, а значит, следующее по величине число, которое можно выразить типом double, должно иметь значащие цифры 10000000...001. (На самом деле чуть-чуть сложнее: ведущая единица не хранится, а подразумевается.) Отсюда выплывает, что 1 + 1e-16 для типа double неотличимо от 1. Поскольку для бóльших чисел увеличивается порядок, при увеличении первого слагаемого машинный эпсилон приблизительно пропорционально увеличивается. Соответственно, 1e16 + 1 будет равно 1e16. В вашем же случае вы на два порядка выше предела: вы прибавляете к 1e18. Давайте ещё проэкспериментируем: http://ideone.com/4XJxFj 1 + 1.110223024625156e-16 == 1 но уже 1 + 1.110223024625157e-16 != 1 Это потому, что 1.110223024625156e-16 -- приближение к 2^-53. Ещё немного информации о числах с плавающей точкой: Хорошая статья на Хабре Классическая статья с теоретическими выкладками, но на английском. Если вам нужно представлять числа с высокой точностью, даже типа long double может не хватить. В этом случае, возможно, придётся применять числа бесконечной точности. Такие числа являются встроенными в некоторых языках (например, Java и C#), а для C и C++ есть хорошие библиотеки, предоставляющие такие числа. Я бы порекомендовал GMP