Vigenerova šifra - C

Místo pro dotazy a rady ohledně programovacích jazyků (C++, C#, PHP, ASP, Javascript, VBS..) a tvorby webových stránek

Moderátor: Mods_senior

popcorn
Level 2.5
Level 2.5
Příspěvky: 391
Registrován: červenec 16
Pohlaví: Muž

Vigenerova šifra - C

Příspěvekod popcorn » 17 zář 2017 09:26

Ahoj, pokouším se udělat vigenerovu šifru v Cčku, ale nějak mi to přestalo fungovat, když zadám do programu větu (s mezerami) Tak se mi úplně program zblázní.. Kde mám chybu? Zdroják:

Kód: Vybrat vše

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>


int main(int argc, char** argv) {


char zprava[100];
int vyber;
int i,j;
char heslo[33];
int hodnota;
char opakovat = 1;

while (opakovat == 1)
{
printf("Zadejte operaci\n");
 
printf("Šifrovat - 1 \n");

printf("Dešifrovat - 2\n");

scanf("%d",&vyber);

if (vyber == 1)    {


  printf("Zadejte zprávu k zašifrování\n");
 fgets (zprava, 100, stdin);
while (getchar() != '\n');
printf("TEXT: ***%s***\n",zprava);


  printf("Zadejte heslo\n");
  scanf("%s", &heslo);
printf("HESLO: ***%s***\n",heslo);

      for(i=0,j=0;i<strlen(zprava);i++,j++) {
          if (zprava[i] == ' ')
            continue;

   

 if(j>=strlen(heslo))

  { 
   j=0;
  }

       if (!isupper(zprava[i]))
       {
        hodnota = ((zprava[i]) - 96) + (heslo[j] - 96);
       }
   
       if (!islower(zprava[i]))     
       {
         hodnota = ((zprava[i]) - 64) + (heslo[j] - 64);   
       }

   printf("%c", 97 + (hodnota % 26));

   }

 }

  else if (vyber == 2) {


  printf("Zadejte zprávu k dešifrování\n");
  scanf("%s", &zprava);

  printf("Zadejte heslo\n");
  scanf("%s",&heslo);

     for(i=0,j=0;i<strlen(zprava);i++,j++)       
                   if (zprava[i] == ' ')
            continue;
     {

   if(j>=strlen(heslo))

    {
      j=0;
    }
       if (!isupper(zprava[i]))
       {
        hodnota = (zprava[i] - 96) - (heslo[j] - 96);
       }
   
       if (!islower(zprava[i]))     
       {
         hodnota = ((zprava[i]) - 64) - (heslo[j] - 64);   
       }
     if
       (hodnota < 0)
     {
       hodnota = hodnota * - 1;
     }

printf("%c", 97 + (hodnota % 26));
}

    printf("\nChcete opakovat?? [1/0]\n");
    scanf("%d", &opakovat);
}
    }
   return (EXIT_SUCCESS);
}



zz.png
Nemáte oprávnění prohlížet přiložené soubory.
Naposledy upravil(a) popcorn dne 17 zář 2017 15:20, celkem upraveno 5 x.


CPU: i5-6500 GPU: Msi RX480 8GB RAM: Crucial 2x8GB MB: MSI B150 PSU: Seasonic S12II-520 CASE: Gladius M35

Reklama
Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 6443
Registrován: prosinec 10
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod faraon » 17 zář 2017 09:46

Hele, nešlo by to s odsazováním? V tomhle se absolutně nedá vyznat :evil:

Tak se na to podíváme:

Kód: Vybrat vše

hodnota = (((zprava[i])- 97) + ((heslo[j])- 97));
...
hodnota = ((zprava[i]) - 96)-(heslo[j] - 96);

To trochu nesedí, ne?

Takže pracuješ pouze s malými písmeny, a co když někdo zadá velké, kde má 'A' hodnotu 65? Nebo když zadá mezeru s hodnotou 32? Nebo jakýkoliv jiný znak který není malé písmeno???

Když už teda (zbytečně) používáš takovou spoustu knihoven, zkus se podívat co všechno obsahuje ctype.h, například https://linux.die.net/man/3/islower ;-)

A potom zkus jednotlivé činnosti oddělit do samostatných funkcí, sifruj() a desifruj() by ten kód hodně zpřehlednilo.
"Pimonte, Pimonte, co jsi ty za pána, že za tebou padla ta majlandská brána, hop, hop, hop.
Ta majlandská brána a ty čtyři mosty, vystav si, Pi­monte, silnější forposty, hop, hop, hop!"

Píseň dobrého vojáka Švejka

popcorn
Level 2.5
Level 2.5
Příspěvky: 391
Registrován: červenec 16
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod popcorn » 17 zář 2017 10:16

Tak kod jsem upravil a mezeru mám řešenou pomocí

Kód: Vybrat vše

if (zprava[i] == ' ')
            continue;


Jak udělat vlastní funkce jsem se ještě nenaučil, takže to nemohu udělat, ale zkusím se na to podívat
CPU: i5-6500 GPU: Msi RX480 8GB RAM: Crucial 2x8GB MB: MSI B150 PSU: Seasonic S12II-520 CASE: Gladius M35

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 6443
Registrován: prosinec 10
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod faraon » 17 zář 2017 10:20

Já bych tam použil spíš něco jako

Kód: Vybrat vše

if (zprava[i]<'a' || zprava[i]>'z')

nebo rovnou

Kód: Vybrat vše

if (!islower(zprava[i]))
"Pimonte, Pimonte, co jsi ty za pána, že za tebou padla ta majlandská brána, hop, hop, hop.
Ta majlandská brána a ty čtyři mosty, vystav si, Pi­monte, silnější forposty, hop, hop, hop!"

Píseň dobrého vojáka Švejka

popcorn
Level 2.5
Level 2.5
Příspěvky: 391
Registrován: červenec 16
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod popcorn » 17 zář 2017 10:41

Tak to bychom měli velká a malá písmena, ale stále mi problém přetrvává, zadám větu a output se zblázní..
output.png
Nemáte oprávnění prohlížet přiložené soubory.
CPU: i5-6500 GPU: Msi RX480 8GB RAM: Crucial 2x8GB MB: MSI B150 PSU: Seasonic S12II-520 CASE: Gladius M35

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 6443
Registrován: prosinec 10
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod faraon » 17 zář 2017 12:35

Asi by to chtělo ujasnit co vlastně má ten program provádět. A také co ve skutečnosti provádí. Co jsi myslel třeba tímhle?

Kód: Vybrat vše

      for(i=0,j=0;i<strlen(zprava);i++,j++)
          if (zprava[i] == ' ')
            continue;

    {

 if(j>=strlen(heslo))

V tom cyklu se nic neudělá, prostě proběhne celý řetězec a skončí.

Chtělo by to kontrolní výpisy, kde se dozvíš co se stalo a kam až ses dostal. Pro začátek si nech vypsat ty řetězce hned po načtení, a nejlépe nějak zvýrazněně, abys je snadno rozeznal od ostatních výpisů:

Kód: Vybrat vše

  printf("Zadejte zprávu k zašifrování\n");
  scanf("%s", &zprava);
printf("TEXT: ***%s***\n",zprava);

  printf("Zadejte heslo\n");
  scanf("%s", &heslo);
printf("HESLO: ***%s***\n",heslo);

A ve druhém případě nezadáš vůbec žádnou zprávu, jsi si jistý že program umí správně reagovat na prázdný řetězec?
"Pimonte, Pimonte, co jsi ty za pána, že za tebou padla ta majlandská brána, hop, hop, hop.
Ta majlandská brána a ty čtyři mosty, vystav si, Pi­monte, silnější forposty, hop, hop, hop!"

Píseň dobrého vojáka Švejka

popcorn
Level 2.5
Level 2.5
Příspěvky: 391
Registrován: červenec 16
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod popcorn » 17 zář 2017 12:43

Kód: Vybrat vše

      for(i=0,j=0;i<strlen(zprava);i++,j++)
          if (zprava[i] == ' ')
            continue;

    {

 if(j>=strlen(heslo))

Tak tohle by mělo přeskočit mezery ve zprávě aby se nezašifrovaly pod nějaký znak.
Ty výpisy myslíš takto?
vypis.png
Nemáte oprávnění prohlížet přiložené soubory.
CPU: i5-6500 GPU: Msi RX480 8GB RAM: Crucial 2x8GB MB: MSI B150 PSU: Seasonic S12II-520 CASE: Gladius M35

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 6443
Registrován: prosinec 10
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod faraon » 17 zář 2017 13:03

No vidíš, už je tam vidět problém, a pořádný! Koukni se na tenhle úsek:
auvajs.png

Takže jedna důležitá informace do budoucna - scanf() je geniální funkce pro načítání čísel a jednotlivých znaků, ale NIKDY jí nepoužívej na řetězec!

A teď bysme měli vyřešit tuhle věc, než budeš pokračovat dalšími chybami. Co s tím provedeme? Napadají mě dvě možnosti:
  1. Použít některou funkci z knihoven, sice optimalizovanou ale zato s rizikem přetečení pole (což je velmi častá a extrémně nebezpečná chyba).
  2. Napsat si vlastní, bezpečnou a o něco pomalejší.
Výhoda té druhé bude v tom, že s její pomocí můžeš načítat zprávu i heslo, a přitom zároveň ošetřit výskyt nevhodných znaků, které se nemají šifrovat. Například těch mezer. A přitom se zrovna dají převést malá písmena na velká, což ti zjednoduší pozdější šifrování...
Nemáte oprávnění prohlížet přiložené soubory.
"Pimonte, Pimonte, co jsi ty za pána, že za tebou padla ta majlandská brána, hop, hop, hop.
Ta majlandská brána a ty čtyři mosty, vystav si, Pi­monte, silnější forposty, hop, hop, hop!"

Píseň dobrého vojáka Švejka

popcorn
Level 2.5
Level 2.5
Příspěvky: 391
Registrován: červenec 16
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod popcorn » 17 zář 2017 13:15

Co takhle třeba použít

Kód: Vybrat vše

fgets (zprava, 100, stdin);
? To by nešlo?
CPU: i5-6500 GPU: Msi RX480 8GB RAM: Crucial 2x8GB MB: MSI B150 PSU: Seasonic S12II-520 CASE: Gladius M35

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 6443
Registrován: prosinec 10
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod faraon » 17 zář 2017 13:20

To by šlo, vyzkoušej to. Mám pocit že tahle funkce načítá i '\n' na konci, to je potřeba ohlídat, pokud by to vadilo.
Nebo si předem nastudovat manuálovou stránku :lol:
"Pimonte, Pimonte, co jsi ty za pána, že za tebou padla ta majlandská brána, hop, hop, hop.
Ta majlandská brána a ty čtyři mosty, vystav si, Pi­monte, silnější forposty, hop, hop, hop!"

Píseň dobrého vojáka Švejka

popcorn
Level 2.5
Level 2.5
Příspěvky: 391
Registrován: červenec 16
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod popcorn » 17 zář 2017 15:00

Tak když tam dám fgets, tak to úplně část se zadáváním zprávy přeskočí a chce to rovnou heslo..
output2.png
Nemáte oprávnění prohlížet přiložené soubory.
CPU: i5-6500 GPU: Msi RX480 8GB RAM: Crucial 2x8GB MB: MSI B150 PSU: Seasonic S12II-520 CASE: Gladius M35

Uživatelský avatar
faraon
Master Level 8
Master Level 8
Příspěvky: 6443
Registrován: prosinec 10
Pohlaví: Muž

Re: Vigenerova šifra - C

Příspěvekod faraon » 17 zář 2017 15:12

Nezůstal ti náhodou '\n' v bufferu po zadání té volby '1'? Zkus hned po tom scanf() buffer vyprázdnit:

Kód: Vybrat vše

while (getchar() != '\n');
"Pimonte, Pimonte, co jsi ty za pána, že za tebou padla ta majlandská brána, hop, hop, hop.
Ta majlandská brána a ty čtyři mosty, vystav si, Pi­monte, silnější forposty, hop, hop, hop!"

Píseň dobrého vojáka Švejka


Zpět na “Programování a tvorba webu”

Kdo je online

Uživatelé prohlížející si toto fórum: CommonCrawl [Bot] a 0 hostů