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 3
Level 3
Příspěvky: 525
Registrován: červenec 16
Pohlaví: Muž
Stav:
Offline

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
zz.png (7.86 KiB) Zobrazeno 1550 x
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.5
Master Level 8.5
Příspěvky: 7356
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

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.
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

popcorn
Level 3
Level 3
Příspěvky: 525
Registrován: červenec 16
Pohlaví: Muž
Stav:
Offline

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.5
Master Level 8.5
Příspěvky: 7356
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

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]))
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

popcorn
Level 3
Level 3
Příspěvky: 525
Registrován: červenec 16
Pohlaví: Muž
Stav:
Offline

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
output.png (6.43 KiB) Zobrazeno 1519 x
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.5
Master Level 8.5
Příspěvky: 7356
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

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?
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

popcorn
Level 3
Level 3
Příspěvky: 525
Registrován: červenec 16
Pohlaví: Muž
Stav:
Offline

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
vypis.png (8.4 KiB) Zobrazeno 1489 x
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.5
Master Level 8.5
Příspěvky: 7356
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

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
auvajs.png (5.22 KiB) Zobrazeno 1480 x

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í...
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

popcorn
Level 3
Level 3
Příspěvky: 525
Registrován: červenec 16
Pohlaví: Muž
Stav:
Offline

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.5
Master Level 8.5
Příspěvky: 7356
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

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:
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

popcorn
Level 3
Level 3
Příspěvky: 525
Registrován: červenec 16
Pohlaví: Muž
Stav:
Offline

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
output2.png (3.43 KiB) Zobrazeno 1460 x
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.5
Master Level 8.5
Příspěvky: 7356
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

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');
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)


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

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 3 hosti