• 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.

0 głosów
89 wizyt
pytanie zadane 10 maja w C i C++ przez xTMx3 Obywatel (1,320 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 przez j23 Mędrzec (175,060 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 przez j23 Mędrzec (175,060 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 przez Oscar Nałogowiec (25,750 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 przez xTMx3 Obywatel (1,320 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 przez Oscar Nałogowiec (25,750 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 przez j23 Mędrzec (175,060 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ź 425 wizyt
pytanie zadane 14 października 2015 w C i C++ przez C☺ndzi Stary wyjadacz (12,100 p.)
0 głosów
3 odpowiedzi 1,098 wizyt
pytanie zadane 31 stycznia 2019 w Java przez burntpoland Nowicjusz (160 p.)
0 głosów
1 odpowiedź 547 wizyt
pytanie zadane 13 grudnia 2018 w Systemy operacyjne, programy przez shotokan Nałogowiec (39,700 p.)

88,355 zapytań

136,952 odpowiedzi

305,666 komentarzy

58,618 pasjonatów

Motyw:

Akcja Pajacyk

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

Sklep oferujący ćwiczenia JavaScript, PHP, rozmowy rekrutacyjne dla programistów i inne materiały

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...