• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Odczytywanie danych z pliku

Object Storage Arubacloud
0 głosów
234 wizyt
pytanie zadane 19 marca 2021 w C i C++ przez Doge Gaduła (3,370 p.)

Witam, podczas uruchamiania programu w konsoli nie wyświetla się pierwsza linia, a ostatnia wyświetla się 2 razy. W kodzie chodzi o to, że dodano 528 i przy odczycie odejmuje te 528 i wyświetla wynik zamiast kodu ASCII jako napis. Pierwszy raz robię coś takiego i nie wiem, gdzie może być błąd.

#include <iostream>
#include <fstream>


using namespace std;

fstream plik;
string linia;
int nr_linii=1, szyfr, zaszyfrowane;

void odszyfrowywanie()
{
    plik.open("szyfr.txt");
    if(plik.good()==false)
    {
        cout<<"Plik nie istnieje"<<endl;
    }
    else
    {
        while(getline(plik,linia))
        {
            plik>>zaszyfrowane;
            cout<<char(zaszyfrowane-528);
            nr_linii++;
        }
    }
    plik.close();
}

int main()
{
    odszyfrowywanie();


    return 0;
}

 

komentarz 19 marca 2021 przez Great Stary wyjadacz (12,360 p.)
Czy możesz wstawić kod szyfrujący?
komentarz 19 marca 2021 przez Doge Gaduła (3,370 p.)

Jasne

#include <iostream>
#include <fstream>

using namespace std;

string napis;
int szyfr;
fstream plik;

void szyfrowanie()
{
    cout<<"Podaj napis do zaszyfrowania: ";
    cin>>napis;

    plik.open("szyfr.txt",ios::out | ios::app);
    for(int i=0;i<napis.size();i++)
    {
        szyfr=int(napis[i]+528);
        cout<<szyfr<<endl;
        plik<<szyfr<<endl;
    }
    plik.close();
}

int main()
{
    szyfrowanie();


    return 0;
}

 

2 odpowiedzi

+1 głos
odpowiedź 19 marca 2021 przez Michał Muzyka Pasjonat (24,080 p.)
wybrane 19 marca 2021 przez Doge
 
Najlepsza

Dzień dobry, sprawdźmy błędy:

Ogólnie chyba wszystko oprócz tego jest dobrze:

while(getline(plik,linia))
{
     plik>>zaszyfrowane;
     cout<<char(zaszyfrowane-528);
     nr_linii++;
}

Przeanalizujmy razem dlaczego:
odczytuje Pan całą linię z pliku, wskaźnik na pozycję w pliku przesuwa się na koniec linii, potem wewnątrz pętli pobiera Pan 1 liczbę całkowitą (4 bajty), odejmuje 528 potem wypisuje ją na ekran, proszę zauważyć, że ta pierwsza pobrana linia zostaje pominięta, ponieważ została już pobrana z pliku, wskaźnik się przesunął, teraz się to zapętla i znowu,
odczytuje Pan od tej pobranej liczby do końca linii, potem pobiera 1 liczbę i tak w kółko,
przykład co się tu dzieje:
PLIK: szyfr.txt
123414 41231 4124 (pobrane przez getline, nie przeprocesowane)
5990 1234512 235 52  (na niebiesko pobrane i przeprocesowane potem pobrane przez getline, nie przeprocesowane)
3430 124224354252

Wydaje mi się że tak chciał Pan to zrobić:

while(plik>>zaszyfrowane)
{
         cout<<char(zaszyfrowane-528);
         nr_linii++;
}
komentarz 19 marca 2021 przez Doge Gaduła (3,370 p.)
Bardzo dziękuję za pomoc
komentarz 19 marca 2021 przez Doge Gaduła (3,370 p.)

@Michał Muzyka,

Mam jeszcze jedno pytanie, ponieważ zedytowałem trochę ten kod

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

using namespace std;

fstream plik;
string linia;
int nr_linii=1, zaszyfrowane, kod;

void odszyfrowywanie()
{
    plik.open("szyfr.txt");
    if(plik.good()==false)
    {
        cout<<"Plik nie istnieje"<<endl;
    }
    else
    {
        while(plik>>zaszyfrowane)
        {
            switch(nr_linii)
            {
        case 1:
            {
                plik>>linia;
                kod=atoi(linia.c_str());
                cout<<"wczytano"<<endl;
            }
        default:
            {
                cout<<"odczytano ";
                cout<<char(zaszyfrowane-kod)<<endl;
            }
            nr_linii++;
            }
        }
    }
    plik.close();
}

int main()
{
    odszyfrowywanie();


    return 0;
}

i wszystko mi działa, poza fragmentem

cout<<char(zaszyfrowane-kod)<<endl;

i czy chodzi o to, że np. nie można odejmować zmiennej od zmiennej? Bo problem jest w tym, że jeżeli wyświetlę zmienną "kod", to jest prawidłowo liczbą, ale jeżeli odejmuję, to zamiast zaszyfrowanych liter, wyskakują różne znaczki, emotki itp.

komentarz 19 marca 2021 przez Michał Muzyka Pasjonat (24,080 p.)
Oczywiście, że można odejmować zmienne od zmiennej, najprawdopodobniej jest to problem tego, że typ char przechowuje wartości od -128 do 127, a litery kodowane są jako liczby z zakresu 65-90 (Duże) i 97-122 (małe) i różnica zaszyfrowane - kod może nie trafiać w te 2 przedziały, wtedy będą wyświetlane jakieś inne znaki. Spróbuje Pan wyświetlić różnicę zaszyfrowane - kod bez rzutowania na char jako int, wtedy zobaczyć czy różnica wykracza poza zakres chara lub zakresy kodowe liter
komentarz 19 marca 2021 przez Doge Gaduła (3,370 p.)

Ma Pan rację, wykraczają poza zakres, tylko nie mogę znaleźć, dlaczego tak się dzieje. Kiedy wczytałem z pliku

21 (zmienna kod)

118 (-21 = 97 - a)

119 (-21 = 98 - b)

120 (-21 = 99 - c)

53 (-21 = 32 - spacja)

to kolejno wychodzą mi wyniki

-97

1

2

-65

i kompletnie nie wiem, skąd one się biorą. Jak jeszcze w pierwszym przypadku kolejność zmiennych się zamieniła, co raczej nie powinno mieć miejsca, tak w pozostałych przypadkach nie mam pojęcia, skąd się wzięły te liczby. W kodzie szyfrującym

#include <iostream>
#include <fstream>
#include <windows.h>
#include <time.h>

using namespace std;

string napis;
int szyfr, kod;
fstream plik;

void szyfrowanie()
{
    cout<<"Podaj napis do zaszyfrowania: ";
    getline(cin,napis);
    napis=napis+" ";

    plik.open("szyfr.txt",ios::out);
    srand(time(NULL));
    kod=rand()%100+1;
    plik<<kod<<endl;
    for(int i=0;i<napis.size();i++)
    {
        if(i==napis.size()-1)
        {
            szyfr=int(napis[i]+kod);
            cout<<szyfr<<endl;
            plik<<szyfr<<" "<<endl;
        }
        else
        {
            szyfr=int(napis[i]+kod);
            cout<<szyfr<<endl;
            plik<<szyfr<<endl;
        }
    }
    plik.close();
}

int main()
{
    szyfrowanie();


    return 0;
}

też trochę zmieniłem, czy może to być wina tego?

komentarz 19 marca 2021 przez Michał Muzyka Pasjonat (24,080 p.)

otóż, aby wykonać dodawanie w dziedzinie liczb int, trzeba zrobić to tak:

szyfr=int(napis[i])+kod;

w aktualnym przypadku jest wykonywane dodawanie w dziedzinie liczb char a dopiero potem następuje rzutowanie na typ int czyli jeżeli wystąpi przepełnienie, będzie miało to wpływ na końcowy wynik.

 

komentarz 19 marca 2021 przez Michał Muzyka Pasjonat (24,080 p.)

Drugim problemem jest też to, że wywołuje Pan pobieranie znaku w switchu,

while(plik>>zaszyfrowane) //tutaj pobierana jest 1 linia
        {
            switch(nr_linii)
            {
        case 1:
            {
                plik>>linia; //tutaj pobierana jest 2 linia
...

w warunku pętli while pobiera Pan liczbę, po czym w switchu pobiera Pan znowu kolejną liczbę, która nadpisuje pobranie kodu, który znajdował się w pierwszej linijce

komentarz 20 marca 2021 przez Doge Gaduła (3,370 p.)

Bardzo dziękuję, zadziałało. Mam jeszcze pytanie odnośnie szyfrowania, ponieważ zedytowałem kod

#include <iostream>
#include <fstream>
#include <windows.h>
#include <time.h>

using namespace std;

string napis;
int szyfr, kod, akcja;
fstream plik;

void szyfrowanie()
{
    cout<<"Witaj w programie szyfrujacym!"<<endl;
    cout<<"Akcje do wybrania:"<<endl;
    cout<<"1 - dopisanie do pliku"<<endl;
    cout<<"2 - zastapienie pliku"<<endl;
    cout<<"Wprowadz akcje: ";
    cout<<"Podaj napis do zaszyfrowania: ";
    cin>>akcja; //tutaj
    if(akcja==1)
    {
        cout<<"1"<<endl;
    }
    else if(akcja==2)
    {
        cout<<"2"<<endl;
    }
    else
    {
        cout<<"inne"<<endl;
    }
    getline(cin,napis);
    napis=napis+" ";

    plik.open("szyfr.txt",ios::out);
    srand(time(NULL));
    kod=rand()%100+1;
    plik<<kod<<endl;
    for(int i=0;i<napis.size();i++)
    {
        if(i==napis.size()-1)
        {
            szyfr=int(napis[i])+kod;
            cout<<szyfr<<endl;
            plik<<szyfr<<" "<<endl;
        }
        else
        {
            szyfr=int(napis[i])+kod;
            cout<<szyfr<<endl;
            plik<<szyfr<<endl;
        }
    }
    plik.close();
}

int main()
{
    szyfrowanie();


    return 0;
}

dodałem zmienną int "akcja" i chciałem zrobić wybieranie akcji, czy dopisywać do pliku, czy zastępować, lecz nie chciało działać, więc postanowiłem wrócić się do starej wersji pliku i powoli testować, czy w ogóle wpisywanie tam działa. I problem tkwi w tym, że nie działa, ponieważ pobiera zmienną, w zależności od wartości wyświetla podany napis, a następnie wyświetla samą zmienną "kod", nie daje pobrać zmiennej "napis". I pytanie brzmi, czy można w zaznaczonym przeze mnie miejscu dopisać owe cin, a jeżeli nie, to czym jest to spowodowane?

komentarz 20 marca 2021 przez Michał Muzyka Pasjonat (24,080 p.)
edycja 20 marca 2021 przez Michał Muzyka

std::cin pobiera znaki ze strumienia do czasu wystąpienia znaku białego tzn. (spacja, tab, enter itp.), a std::getline pobiera do znaku enter(EOL, '\n').
Przy mieszaniu użycia std::cin i std::getline pojawiają się anomalie, aktualnie dzieje się taka sytuacja
wpisuje Pan: 1 potem "napisdozaszyfrowania", w buforze pojawia się to tak:
1'\n'napisdozas zyf rowania'\n'
std::cin pobiera 1 w buforze zostaje:
'\n'napisdozas zyf rowania'\n',
std::getline pobiera pustą linie, bo pobiera znaki do czasu wystąpienia znaku końca linii.
aby zapobiec tej sytuacji trzeba odrzucić 1 znak po wywołaniu std::cin

cin>>akcja; //tutaj
cin.ignore();
if(akcja==1)

 

0 głosów
odpowiedź 19 marca 2021 przez Great Stary wyjadacz (12,360 p.)

Odpowiedź już padła, ale wrzucę trochę schludniejszą wersję kodu:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

void odszyfrowywanie()
{
    ifstream plik("szyfr.txt");
    if (not plik.is_open())
    {
        cout << "Plik nie istnieje" << endl;
        return;
    }

    int zaszyfrowane;
    while (plik >> zaszyfrowane)
    {
        cout << static_cast<char>(zaszyfrowane - 528);
    }
}

int main()
{
    odszyfrowywanie();
}

komentarz 19 marca 2021 przez Doge Gaduła (3,370 p.)
Bardzo dziękuję za pomoc

Podobne pytania

0 głosów
0 odpowiedzi 983 wizyt
pytanie zadane 3 grudnia 2019 w C i C++ przez Glitterfrost Nowicjusz (210 p.)
0 głosów
1 odpowiedź 954 wizyt
0 głosów
0 odpowiedzi 198 wizyt
pytanie zadane 6 maja 2020 w C i C++ przez Rajzok Początkujący (390 p.)

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...