César's cipher - problem with letters and spaces

6

I'm doing an exercise on the cesar figure below:

#include<stdio.h>#include<string.h>main(){charfrase[200];printf("String: ");
  gets(frase);

  for(int i=0; i < strlen(frase); i++){

   if(frase[i] == 'x')
     frase[i] = 'A';
   if(frase[i] == 'y')
     frase[i] = 'B';
   if(frase[i] == 'z')
     frase[i] = 'C';

     frase[i] = frase[i] + 3;
  }

  printf("String: %s", frase);
}

Problems:

  • If I try to convert the letters' XYZ 'can not appear' [/] Note: I tried to include if () for the sentence case [i] == 'y' it would store the letter 'B' in the case, but it did not work.

  • When I use spaces, # appears in their place.

  • asked by anonymous 20.06.2017 / 04:21

    4 answers

    8

    If I understand the problem, you need to make exception for the last characters. I used to discard something out of what is expected.

    I made the most idiomatic code C by walking a pointer instead of taking its size. Do not use strlen() where you do not need .

    If you use another data entry mechanism like fgets() it will read the data more appropriately , including space. Scanf() is only for testing and trivial use.

    I did according to the statement, if other characters need to be dealt you need to tinker with the code to add them. It does not have a clear criterion of what to do in cases where there are characters that leave the range, I chose to leave it as it is.

    #include <stdio.h>
    
    int main() {
        char frase[200];
        printf("String: ");
        scanf("%200s", frase);
        for (char *i = frase; *i != '
    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char frase[200];
        printf("String: ");
        scanf("%200s", frase);
        for (int i = 0; i < strlen(frase); i++) {
            if (frase[i] >= 'A' && frase[i] <= 'Z') { //só altera se estiver na faixa correta
                if (frase[i] > 'W') { //trata os casos que precisam girar a tabela
                    frase[i] += -23;
                } else {
                    frase[i] += 3;
                }
            }
        }
        printf("String: %s", frase);
    }
    
    '; i++) { *i = *i < 'A' || *i > 'Z' ? *i : (((*i - 65) + 3) % 26) + 65; } printf("String: %s", frase); }

    See running on ideone . And at Coding Ground . Also put it in GitHub for future reference .

    If you want to do not idiomatic, it has like, it works, technically it's not wrong, but that's not the way it's done in C. If it's to do it this way it's better to use another language.

    #include <stdio.h>
    
    int main() {
        char frase[200];
        printf("String: ");
        scanf("%200s", frase);
        for (char *i = frase; *i != '
    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char frase[200];
        printf("String: ");
        scanf("%200s", frase);
        for (int i = 0; i < strlen(frase); i++) {
            if (frase[i] >= 'A' && frase[i] <= 'Z') { //só altera se estiver na faixa correta
                if (frase[i] > 'W') { //trata os casos que precisam girar a tabela
                    frase[i] += -23;
                } else {
                    frase[i] += 3;
                }
            }
        }
        printf("String: %s", frase);
    }
    
    '; i++) { *i = *i < 'A' || *i > 'Z' ? *i : (((*i - 65) + 3) % 26) + 65; } printf("String: %s", frase); }

    I voted for ideone , but I would rather not have written like this.

        
    20.06.2017 / 06:14
    2

    I think an easier way to explain it would be:

    int main(){
    
      char frase[200];
    
      strncpy(frase, "SUA FRASE QUALQUER", 200);
    
      for(int i=0; i < strlen(frase); i++){
    
          if(frase[i] >= 65 && frase[i] <= 90){
    
            frase[i] = (((frase[i] - 65) + 3) % 26)  + 65;
    
          }else{
              frase[i] = 32;
          }
    
      }
    
      printf("String: %s", frase);
    }
    

    Try this.

    All uppercase letters supported in ASCII then between 65 and 90, in decimal, so the if(frase[i] >= 65 && frase[i] <= 90){ is used, otherwise it will change to a space, in else{} .

    frase[i] = (((frase[i] - 65) + 3) % 26)  + 65;
    

    The Caesar cipher itself is basically moving the alphabet by 3 characters.

    The problem is that ASCII A is 65. So I used (frase[i] - 65) , so A will be 0 , because 65 - 65 . Then it is summed to "key" , thus 0 + 3 , then the rest of the division is done by the number of characters of the 3 % 26 alphabet, which will give 3 and then it is summed with 65 , so it will give 68 which is D in ASCII.

    If it were Z it would be exactly 90 - 65 , then 25 + 3 and then would 28 % 26 which will result in 2 . Then the Z will become a C , after all it is the result of 65 + 2 .

        
    20.06.2017 / 14:32
    2

    Based on the article from wikipedia , I implemented the functions of cifragem and decifragem a from a chave , represented by an integer value.

    Note that encryption and decryption consider only letters, ignoring all other types of characters.

    Follow the Tested Code:

    #include <stdio.h>
    #include <string.h>
    
    void cifrar( char * saida, const char * entrada, int chave )
    {
        int i = 0;
        int tam = strlen(entrada);
    
        for( i = 0; i <= tam; i++ )
        {
            if( (entrada[i] >= 'a') && (entrada[i] <= 'z') )
            {
                saida[i] = (((entrada[i] - 'a') + chave) % 26) + 'a';
            }
            else if( (entrada[i] >= 'A') && (entrada[i] <= 'Z') )
            {
                saida[i] = (((entrada[i] - 'A') + chave) % 26) + 'A';
            }
            else
            {
                saida[i] = entrada[i];
            }
    
        }
    }
    
    
    void decifrar( char * saida, const char * entrada, int chave )
    {
        int ch = 0;
        int i = 0;
        int tam = strlen(entrada);
    
        for( i = 0; i <= tam; i++ )
        {
            if( (entrada[i] >= 'a') && (entrada[i] <= 'z') )
            {
                ch = (entrada[i] - 'a') - chave;
                if( ch < 0 ) ch += 26;
                saida[i] = ch + 'a';
            }
            else if( (entrada[i] >= 'A') && (entrada[i] <= 'Z') )
            {
                ch = (entrada[i] - 'A') - chave;
                if( ch < 0 ) ch += 26;
                saida[i] = ch + 'A';
            }
            else
            {
                saida[i] = entrada[i];
            }
    
        }
    }
    
    int main( int argc, char * argv[] )
    {
        char original[] = "Um pequeno jabuti xereta viu dez cegonhas felizes!";
    
        char cifrado[100] = {0};
        char decifrado[100] = {0};
    
        cifrar( cifrado, original, 3 );
        decifrar( decifrado, cifrado, 3 );
    
        printf( "Original: %s\n", original );
        printf( "Cifrado: %s\n", cifrado );
        printf( "Decifrado: %s\n", decifrado );
    
        return 0;
    }
    
    /* fim-de-arquivo */
    

    Testing:

    $ ./cesar
    Original: Um pequeno jabuti xereta viu dez cegonhas felizes!
    Cifrado: Xp shtxhqr mdexwl ahuhwd ylx ghc fhjrqkdv iholchv!
    Decifrado: Um pequeno jabuti xereta viu dez cegonhas felizes!
    
        
    20.06.2017 / 16:01
    1

    You should write your conditional differently

    if(frase[i] == 'x')
         frase[i] = 'A';
    else if(frase[i] == 'y')
        frase[i] = 'B';
    else if(frase[i] == 'z')
        frase[i] = 'C';
    else
        frase[i] = frase[i] + 3;
    

    In this way the increment will only be made if the letters are different from x , y and z .

    According to your César Cipher conversion table image, blanks may be disregarded. Using scanf("%200s", frase); like bigown suggested solving the problem

        
    20.06.2017 / 13:56