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

Szyfrowanie danych z pliku i zapis do drugiego pliku.

Object Storage Arubacloud
0 głosów
516 wizyt
pytanie zadane 10 maja 2022 w C i C++ przez xTMx3 Obywatel (1,560 p.)

Witam,

ostatnio dostałem takie takie zadanie do wykonania: 

"Proszę napisać program dokonujący szyfrowania/deszyfrowania zawartości pliku jednoznakowym kluczem (Program powinien być uruchamiany z poziomu procesora poleceń ).

Wymaganie 1: wykorzystanie argumentów funkcji main. Program powinien być wywołany z czterema parametrami: rodzaj operacji: s – szyfrowanie, d –deszyfrowanie, drugi - nazwa pliku do szyfrowania/deszyfrowania, trzeci - nazwa pliku zaszyfrowanego/odszyfrowanego, czwarty - jednoznakowy klucz.

Wywołanie powinno wyglądać w następujący sposób:

NazwaProgramu s plik1 plik2 X lub NazwaProgramu d plik1 plik2 X 

Każde inne wywołanie powinno zostać uznane za nieprawidłowe i spowodować wyprowadzenie informacji o prawidłowym sposobie wywołania programu.

 

Program ma działać w pewien specyficzny sposób: 

Wymaganie 2 i 3 (dynamiczna alokacja pamięci oraz blokowy i znakowy odczyt i zapis pliku): Jeżeli tylko się to uda, program powinien najpierw załadować zawartość pliku do dynamicznie zaalokowanej tablicy znaków. Potem dokonać operacji szyfrowania/deszyfrowania znaków zapisanych w tablicy i zapis wyników do pliku wynikowego. Może się jednak zdarzyć, że plik będzie tak duży, że nie uda się zaalokować tablicy równiej rozmiarowi pliku. Wtedy program powinien wykonać operację szyfrowania/deszyfrowania odczytując zawartości pliku znak po znaku. Wymaganie 4: Proszę ładnie podzielić program na funkcje, zadbać o czytelność kodu."

Niestety profesor nie zrealizował tego tematu na wykładzie, a dał jedynie materiały do samodzielnej nauki. Bazując na tych materiałach napisałem taki kod:

#include <stdio.h>
#include <string.h>

char err_mess[] = "\nBlad wywolania programu\n"
                  "\nparametry: [s|d]  nazwa_pliku_z_danymi  nazwapliku_wynikowego  jednoznakowy_klucz\nWszystkie parametry sa obowiazkowe"
                  "\n";

long int ilosc_znakowPliku(FILE * file) //Funkcja zliczajaca znaki w pliku
{
    long int counter = 0;

    while( ! feof( file ) )
    {
        putchar( fgetc( file ) );
        counter++;
    }
    return counter;
}

void szyfrowanie( FILE * file, FILE * file2, long int dl, char k ) // Funkcja szyfrujaca
{
    char * buffer = new char [dl];

    if( dl == ilosc_znakowPliku(file) /* ?? */ ) //Jesli uda sie zmiescic zawartosc calego pliku w tablicy
    {
        while( fgets( buffer, dl, file ) != NULL )
        {
            for(int i = 0; buffer[i] != '\0'; ++i)
            {
                buffer[i] = buffer[i] ^ k;
            }
            fputs(buffer, file2);
            printf( "Napis po wykonaniu zadanej operacji: %s", buffer );
        }
    }
    else //Jesli nie uda sie zmiescic calego pliku w tablicy
    {
        char znak;

        while( fgetc( file ) != NULL )
        {
            znak = fgetc(file);
            znak = pow(znak, k);
            fputc(znak, file2);
        }
    }
    delete [] buffer;
}

int main(int argc, char *args[] )
{
    char file_name[ 256 ];    /* Zapamietuje nazwe pierwszego pliku */
    char file_name2[ 256 ];   /* Zapamietuje nazwe drugiego pliku   */
    FILE * file;              /* Wskaznik pliku pierwszego          */
    FILE * file2;             /* Wskaznik pliku drugiego            */

    if( argc != 5 || args[1][1] != '\0' || args[4][1] != '\0') //Sprawdzam poprawnosc paramterow
    {
        printf( err_mess );
        return EXIT_FAILURE;
    }
    else //Jesli sa poprawne to zapisuje nazwe plikow do zmiennych
    {
        strcpy( file_name, args[ 2 ] );
        strcpy( file_name2, args[ 3 ] );
    }
    if( ( file = fopen( file_name, "r+t")) != NULL && ( file2 = fopen( file_name2, "r+b")) != NULL) //Otwieram oba pliki
    {
        printf("\nNapis przed zaszyfrowaniem: "); //Wyswietlam napis przed zaszyfrowaniem i wypisuje jego dlugosc

        switch( args[1][0] )
        {
        case 's' :
            printf("%d",ilosc_znakowPliku(file));
            fclose(file);
            fopen ( file_name, "r+t" );
            printf("\n\nNapis po zaszyfrowaniu: ");
            szyfrowanie(file, file2, ilosc_znakowPliku(file), args[4][0]); //Szyfruje plik1 i zapisuje wynik do pliku2
            break;
        case 'd' :
            printf("%d",ilosc_znakowPliku(file));
            fclose(file);
            fopen ( file_name, "r+t" );
            szyfrowanie(file2, file, ilosc_znakowPliku(file), args[4][0]); //Szyfruje plik2 i zapisuje wynik do pliku1
            break;
        default:
            printf( err_mess ); // W przypadku podania zlych parametrow wyswietlam blad
            break;
        }
        fclose( file ); //Zamykam oba pliki
        fclose( file2 );

        puts( "\n---- Press Enter to quit ----" );
        ( void )getchar();
        return EXIT_SUCCESS;
    }
    else //Jesli wczesniej nie udalo sie otworzyc pliku, wyswietlam blad i koncze dzialanie programu
    {
        printf( err_mess );
        puts( "\n---- Press Enter to quit ----" );
        ( void )getchar();
        return EXIT_FAILURE;
    }
}

Niestety z racji tego, że dosyć kiepsko idzie mi nauka z samej teorii, program nie działa tak jak bym chciał. Kiedy go uruchamiam z wiersza poleceń, dzieje się takie coś:

Samo wyświetlenie napisu z pliku działa poprawnie, ilość znaków obok również, ale niestety nic poza tym nie jest takie jak powinno.  

Póki co, jedyne co może być błędem i przychodzi mi do głowy, to pierwszy warunek w funkcji szyfrowanie (tam gdzie znaki zapytania w kodzie), bo jeśli się nie mylę to chyba zawsze będzie on spełniony w takiej postaci, a miało to mieć za zadanie sprawdzać, czy cała zawartość pliku zmieściła się do tablicy. Nie wiem niestety co jeszcze zrobiłem źle skoro nie działa.

W związku z tym chciałbym prosić o pomoc kogoś bardziej rozeznanego, żeby spojrzał na ten kod i wskazał co zrobiłem źle, ewentualnie podpowiadając jeszcze co powinienem zrobić, żeby to poprawić.

Dziękuję z góry za wszelką pomoc, pozdrawiam. 

 

1 odpowiedź

0 głosów
odpowiedź 10 maja 2022 przez j23 Mędrzec (194,920 p.)

W funkcji ilosc_znakowPliku zapomniałeś przewinąć strumień na początek. Teraz po użyciu tej funkcji każda próba odczytu zakończy się niepowodzeniem. Daj przed return wywołania:

clearerr(file);
rewind(file);

Funkcja szyfrowanie to jakieś poplątanie z pomieszaniem. Po co alokujesz bufor na cały plik, skoro i tak czytasz tylko po linii?

Z drugiej strony wymóg 2/3 jest bez sensu, bo co to znaczy, że plik się nie zmieści w buforze? Ten bufor ma jakąś ograniczoną wielkości, czy może plik do zaszyfrowania będzie taki ogromny, że RAM-u nie starczy?

Jeśli piszesz w C, to tego new[] i delete[] nie powinno tam być.

 

komentarz 12 maja 2022 przez j23 Mędrzec (194,920 p.)

Gdybyś kompilował w kompilatorze C a nie C++, to problemu by nie było, a tak musisz jawnie rzutować:

char * buffer = (char*)malloc(dl);

Dlaczego C? Bo twój kod wygląda na kod napisany w C.

komentarz 12 maja 2022 przez Oscar Nałogowiec (29,290 p.)

@xTMx3,  Tak jak wspomniałem, jeśli chcesz używać new musisz użyć parametru nothrow.

new(std::nothrow) char[dl]

Bez takiego parametry new rzuci wyjątkiem - czyli program od razu zostanie zakończony (bo nie obsługujesz wyjątków) - gdy nie będzie mógł zaallokować pamięci. Normalnie to nie jest wielki problem - jak nie daje się zaalokować pamięci zwykle nie ma sensu dalej działać, ale akurat w twoim przypadku kontynuowanie ma sens.

Ale zgadzam się z @j23 - lepiej zostań przy malloc/free. Masz kod zasadniczo w czystym C, niech już takim zostanie.

komentarz 12 maja 2022 przez xTMx3 Obywatel (1,560 p.)
Na prawdę jest to pisane w C? Wyjaśniało by to w sumie skąd jakieś dziwne problemy ze zrozumieniem wszystkiego u mnie, bo od początku semestru zajęcia z programowania miały na celu nauczenie nas C++'a.

Tydzień po tygodniu, wszystko było z C++, potem dostałem to zadanie z szyfrowaniem (i tutaj ta dziwna anomalia, bo materiały które dostałem były pisane, tak jak to twierdzicie, w C). A dwa dni temu, na kolejnych zajęciach przeszliśmy do dalszej części, wprowadzenie do obiektów, ale już z powrotem w C++.

Teraz już kompletnie pogubiłem się, w jakiej wersji to powinienem w ogóle wysłać, bo skoro uczyć mieli nas przez cały semestr C++, to z tego by wynikało, że ma być C++, ale z kolei to jedno zadanie różni się "wyglądem" od reszty.

Albo ja czegoś nie rozumiem i ominąłem jakiś duży przeskok w nauce, pomimo że nie opuściłem ani jednych zajęć, albo coś tu nie gra i jest namotane.

W każdym razie... Coś spróbuję wykombinować.

Dziękuję wam serdecznie za pomoc.
komentarz 12 maja 2022 przez Oscar Nałogowiec (29,290 p.)
C jest podzbiorem C++ (oczywiście chronologicznie to C++ jest rozszerzeniem C), kod w C jest też automatycznie kodem w C++, jedynie pewne restrykcje są silniejsze - coś co w C jest warningiem, w C++ może być już błędem. Ale "ładny" kod w C kompiluje się jako C++ bez problemu.
komentarz 13 maja 2022 przez j23 Mędrzec (194,920 p.)

@xTMx3, 

Na prawdę jest to pisane w C?

W typowym C++ użyłbys strumieni std::cout, std::ifstream i std::ofstream zamiast printf, fopen, fwrite, fread itd. std::string zamiast tablic char[] i std::vector zamiast ręcznego zarządzania pamięcią przez malloc/free.

Podobne pytania

0 głosów
1 odpowiedź 719 wizyt
pytanie zadane 14 października 2015 w C i C++ przez C☺ndzi Stary wyjadacz (12,100 p.)
0 głosów
1 odpowiedź 386 wizyt
pytanie zadane 12 stycznia 2023 w C# przez DominikPie Użytkownik (770 p.)
+1 głos
1 odpowiedź 528 wizyt

92,555 zapytań

141,403 odpowiedzi

319,557 komentarzy

61,940 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!

...