Ayuda con C please!

Ejercicio 5. Encriptamensaje.c
Realizar programa en el que encriptar un mensaje de texto. Parametro:
1. Mensaje cifrado
2. Los que queramos
La salida debe ser una cadena de texto ilegible e inentendible.
Debe tener posibilidad de encriptar o desencriptar un mensaje.
En pantalla debe salir menu pidiendo
1. Encriptar
2. Descodificar
Opcion elegida (1 o 2)


Mi idea era que le metiera el mensaje en tipo char, y lo mostrara como int, y despues al desencriptar lo mostrara como char.., pero he realizado esta prueba, y no me guarda los datos que le meto, es el primer programa que diseño, y la verdad esque cuesta empezar xD
Ya que estás empezando, lo más sencillo es usar el cifrado César (adivina quién lo inventó).

Consiste en sustituir cada caracter por el X veces posterior, siendo X la clave. Por ejemplo, si estás usando la clave 2, el mensaje "hola" pasaría a ser "jqmc", para descifrar sólo tendrías que restar la clave.

Los parámetros serían la clave y el mensaje, pasas el mensaje a minúsculas o mayúsculas (supongamos que eliges mayúsculas) y, después:
- Si quieres cifrar sólo tienes que sumar la clave a cada caracter, teniendo en cuenta que en ascii la 'A' es el 65 y la 'Z' es el 90 (http://es.wikipedia.org/wiki/Ascii#Cara ... bles_ASCII), tienes que aplicar módulos y demás para que cada caracter del mensaje cifrado esté entre esos valores. Es muy sencillo, pero sácalo tú.
- Si quieres descifrar sólo tienes que hacer lo anterior pero a la inversa, es decir, restar la clave de modo que todos los caracteres te queden entre las mayúsculas, para que te dé el mensaje original.
- Para ambos, tienes que controlar los espacios, puedes eliminarlos o dejarlos igual, o lo que se te ocurra.

Otra opción sería usar el cifrado polybios, que también es sencillo y el mensaje cifrado son números del doble de la longitud del mensaje original.

Por cierto, mírate las cadenas en c, en tu código estás manejando un único caracter.
Buenas. Muchas gracias.

Voy a leerme todos los apuntes, que tengo por aqui, y me pongo con ello, creo que si sé hacerlo, ahora postearé mis avances xD
_MoeB_ está baneado por "Troll brutal"
Unas cosillas; cómo bien dice amachamu, tan sólo estás leyento un character por lo que debes utilizar una string de characteres para leer toda la frase a encriptar.
Luego si quieres una encriptación sencilla lo que yo haría sería crear una matrix en la que podrías ir cambiando cada character por otro predeterminado. Este método te ayudaría luego a descifrar de nuevo la frase.

Ah, y una cosa, no olvides nunca el poner una opción en cada menú de usuario para asegurarte de que el usuario ha introducido una opción correcta. Por ejemplo cuando pides que pongan 1 para encriptar o 2 para desencriptar ¿ Que pasaría si ponen 5 ?
Es una chorrada, pero es algo que los profes aprecian ya que demuestras que has sospesado todas las opciones en la GUI del programa. Además no cuesta nada, ya que serían un par de lineas más ;)
Si quieres cifrar sólo tienes que sumar la clave a cada caracter, teniendo en cuenta que en ascii la 'A' es el 65 y la 'Z' es el 90


nose muy bien como hacer esto, las cadenas no las domino mucho, me es mas intuitivo declarar 100 variables antes que una cadena xDD


declaro una cadena con todas las letras

char cad[28] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','ñ','o','p','q','r','s','t','u','v','w','x','y','z','\0'};)

y ahora creo otra cadena con otras letras.., estoy un poco perdido


EDIT:

Para cambiar los valores ASCII lo puedo hacer con un for no?, pero nose muy bien como
jackerr escribió:
Si quieres cifrar sólo tienes que sumar la clave a cada caracter, teniendo en cuenta que en ascii la 'A' es el 65 y la 'Z' es el 90


nose muy bien como hacer esto, las cadenas no las domino mucho, me es mas intuitivo declarar 100 variables antes que una cadena xDD


declaro una cadena con todas las letras

char cad[28] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','ñ','o','p','q','r','s','t','u','v','w','x','y','z','\0'};)

y ahora creo otra cadena con otras letras.., estoy un poco perdido


yo no soy un experto en C ni mucho menos, pero en C tu le puedes sumar un número a un char y te lo desplaza esas posiciones según el código ascii (creo). si escribes: letra = 'A'; letra_1 = letra + 3; el resultado de letra_1 sería D, porque es "tres caracteres ascii mayor", lo desplazó tres hacia la derecha. de esta forma tendrías la letra A encriptada, para desencriptarla tendrías que hacer letra_1 - 3 (donde pongo 3 pon cualquier número, y sería la clave). si aplicas eso uno a uno a todos los char de un string con la clave correcta ya te da la frase original, si le aplicas la clave incorrecta te da una cadena ininteligible.

un salu2
(mensaje borrado)
(mensaje borrado)
Yo para hacer el cifrado cesar sin preocuparme de ASCII haría lo siguiente:

Te declaras un vector con las letras que vayas a usar

char abc[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";

Ahora si te fijas, tienes un vector en el que abc[0] = A, abc[1] = B, ... , abc[26] = Z
Para hacer el cifrado Cesar pides un mensaje y lo guardas en una cadena, pides la clave y la guardas en un entero.

Luego solo tienes que recorrer el mensaje que quieres codificar letra a letra y para cada una, la buscas en el vector abc[], le sumas la clave y le haces mod 27 (o la longitud de tu alfabeto).

Por ejemplo, si la primera letra a codificar es una Z y la clave es 3 se corresponderia con abc[26], le sumas 3 (29) y le haces el mod 27 (2) que se corresponde con la B.
te voy a medio hacer los deberes poniéndote un ejemplo de un cesar/Vigenère que esta basado en un alfabeto de destino de 94 caracteres, correspondientes a los imprimibles del ascii de 7bits menos el espacio:

//generamos el pass a partir de la clave
for(i=0;i<max_string_size-1;) for(n=0;n<max_string_size-1&&clave[n]!='\0'&&clave[n]!='\n';n++,i++) pass[i]=clave[n];;
pass[i]='\0';

//encriptar
for(i=0;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++)salida[i]=(entrada[i]+pass[i]-66)%94+33;
salida[i]='\0';

//desencriptar
for(i=0;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++)salida[i]=(94+entrada[i]-pass[i])%94+33;
salida[i]='\0';

//preencriptado para hacerlo mas robusto
salida[0]=entrada[0];
for(i=1;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++)salida[i]=33+(entrada[i]+entrada[i-1]-66)%94;
salida[i]='\0';

//postencriptar si no es ininteligible
salida[0]=entrada[0];
for(i=1;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++)salida[i]=33+(94+entrada[i]-salida[i-1])%94;
salida[i]='\0';


Por cierto el espacio se solapa con '~' y el alfabeto no se genera ya que se trabaja con los caracteres directamente.

//desencripra transformando '~' en espacio
for(i=0;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++) if((salida[i]=33+(94+entrada[i]-pass[i])%94)=='~')salida[i]=' ';;
salida[i]='\0'


//postencriptar transformando '~' en espacio
salida[0]=entrada[0];
for(i=1;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++) if((salida[i]=33+(94+entrada[i]-salida[i-1])%94)=='~')salida[i]=' ';;
salida[i]='\0';
Elohe gracias, pero me resulta complicado hacerlo así, ya que es el primero que diseño desde 0 xD..

Korso10 me gusta esa manera parece facil, lo de pedir clave me lo saltaría e inicializaria directamente el entero a 2 por ejemplo.

la cosa es una vez que ya tengo mi mensaje en una cadena, y en otra cadena el abecedario, como puedo recorrer la cadena, y sustituir caracteres uno a uno.. que poco nivel tengo, voy a googlear
Con un bucle for, puedes calcular la longitud de la cadena con strlen (http://c.conclase.net/librerias/funcion.php?fun=strlen). Ten en cuenta que el primer caracter de la cadena es lacadena[0], no lacadena[1].
amuchamu escribió:Con un bucle for, puedes calcular la longitud de la cadena con strlen (http://c.conclase.net/librerias/funcion.php?fun=strlen). Ten en cuenta que el primer caracter de la cadena es lacadena[0], no lacadena[1].



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mensaje[300];
int a;
char micadena[]="abcdefghijklmnñopqrstuvwxyz";

int main ()
{
     printf("Pulsa 1 para encriptar o 2 para desencriptar");
     scanf("%d",&a);
     if(a=1)
           {
           printf("Dame un Mensaje\n");
           scanf("%s",&mensaje);
           getchar();
            printf("Tu mensaje encriptado es %s\n"),mensaje;
            }
    else
    {
    printf("Dame el mensaje encriptado\n");
    scanf("%s",&mensaje);
    getchar();
    printf("el mensaje desencriptado es %s\n",&mensaje);
}
}   


Esto es lo que llevo, pero ya me pierdo, nose como empezar a sustituir
He echo un prototipo funcional a partir del tuyo con algunos cambios y añadido a lo que había puesto, fíjate que no me importa saber el tamaño de la cadena y si el máximo posible reservado en este caso ya que solo uso memoria estática y los valores son forzados, la razón es que digo que se a llegado al final de vector si se detecta un '\0' o un '\n', la función strlen() busca el '\0' para determinar el final del vector. Fíjate como van mis funciones e intenta comprenderlas que te ayudara.

#include <stdio.h>
#include <stdlib.h>
#define max_string_size 300

void encriptar(char* entrada, char *salida, char* clave){
    int i,n;
    char pass[max_string_size]="";
    char noclave[2]="!";
    if(clave==NULL||clave[0]=='\n'||clave[0]=='\0') clave = noclave;
    //generamos el pass a partir de la clave
    for(i=0;i<max_string_size-1;) for(n=0;n<max_string_size-1&&clave[n]!='\0'&&clave[n]!='\n';n++,i++) pass[i]=clave[n];;
    pass[i]='\0';
    //desencriptar
    for(i=0;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++)salida[i]=(entrada[i]+pass[i]-66)%94+33;
    salida[i]='\0';
    }

void desencriptar(char* entrada, char *salida, char* clave){
    int i,n;
    char pass[max_string_size]="";
    char noclave[2]="!";
    if(clave==NULL||clave[0]=='\n'||clave[0]=='\n') clave = noclave;
    //generamos el pass a partir de la clave
    for(i=0;i<max_string_size-1;) for(n=0;n<max_string_size-1&&clave[n]!='\0'&&clave[n]!='\n';n++,i++) pass[i]=clave[n];;
    pass[i]='\0';
    //desencriptar
    for(i=0;i<max_string_size-1&&entrada[i]!='\0'&&entrada[i]!='\n';i++) if((salida[i]=33+(94+entrada[i]-pass[i])%94)=='~')salida[i]=' ';;
    salida[i]='\0';
    }


int main ()
{
     int a;
     char mensaje[max_string_size];
     char salida[max_string_size];
     char clave[max_string_size];
     do{
     printf("Pulsa 1 para encriptar, 2 para desencriptar o 0 para salir: ");
     scanf("%d",&a);
     fflush(stdin);
     if(a==1){
        printf("Dame un Mensaje:\n");
        scanf("%s",mensaje);
        fflush(stdin);
        printf("Dame la clave:\n");
        scanf("%s",clave);
        fflush(stdin);
        encriptar(mensaje,salida,clave);
        printf("Tu mensaje encriptado es:\n%s\n\n",salida);
        }
    else if(a==2){
        printf("Dame el mensaje encriptado\n");
        scanf("%s",mensaje);
        fflush(stdin);
        printf("Dame la clave:\n");
        scanf("%s",clave);
        fflush(stdin);
        desencriptar(mensaje,salida,clave);
        printf("el mensaje desencriptado es\n%s\n\n",salida);
        }
    }while(a!=0);
}


//buscar primera ocurrencia de carácter en una cadena
int buscar_caracter(char *cadena,char caracter){
int i;
for(i=0;cadena[i]!=caracter&&cadena[i]!='\0';i++);
if(cadena[i]!=caracter) return -1;
return i;
}
jackerr escribió:
amuchamu escribió:Con un bucle for, puedes calcular la longitud de la cadena con strlen (http://c.conclase.net/librerias/funcion.php?fun=strlen). Ten en cuenta que el primer caracter de la cadena es lacadena[0], no lacadena[1].



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mensaje[300];
int a;
char micadena[]="abcdefghijklmnñopqrstuvwxyz";

int main ()
{
     printf("Pulsa 1 para encriptar o 2 para desencriptar");
     scanf("%d",&a);
     if(a=1)
           {
           printf("Dame un Mensaje\n");
           scanf("%s",&mensaje);
           getchar();
            printf("Tu mensaje encriptado es %s\n"),mensaje;
            }
    else
    {
    printf("Dame el mensaje encriptado\n");
    scanf("%s",&mensaje);
    getchar();
    printf("el mensaje desencriptado es %s\n",&mensaje);
}
}   


Esto es lo que llevo, pero ya me pierdo, nose como empezar a sustituir


a ver, si es la primera practica que hace no creo que la mejor idea sea empezar a meterle punteros ni separar funciones, primero habra que empezar simplemente por ir cogiendole el punto al C.
yo te recomiendo que sigas por donde vas, una sola funcion y a lo facil, ya tendras tiempo de matarte mas adelante. dos cosas, despues del scanf dentro del ifcreo que el getchar sobra, eso te va a pedir que metas otro dato. la otra, if a=1, eso está mal. es de los errores más tipicos de C, si escribes eso, lo que estas haciendo es hacer dentro del if una asignación, a=1. lo que tienes que poner es if a==1. uno de los problemas puede venir por ahí.
yo te aconsejo que primero introduzcas la cadena, luego selecciones encriptar o desesncriptar, y para encriptar hagas un for que recorra la cadena uno a uno, la sintaxis no se si es justo esa, en C estoy un poco pez,
for i=0;1;strlen(cadena)
{
cadena_encriptada[i] = cadena[i]+clave;
}

y para desencriptar pues lo mismo:
for i=0;1;strlen(cadena)
{
cadena_desencriptada[i] = cadena[i]-clave;
}

algo asi debería funcionar, ya que un string es como un array de chars (creo). el único problema que le veo es la inicialización de las variables (por su longitud me refiero) ya que al no poder en C modificar su tamaño en tiempo de ejecución sin usar punteros igual hace algo un poco raro en los caracteres sin usar...
suerte, un saludo.
Bueno, ya que le hemos hecho los deberes, pongo mi solución, que ya lo tenía hecho de hace años :P

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

int main(char argc, char *argv[]){
   
   // parámetros
   
   if (argc != 3){
   printf("Error, número de parámetros incorrecto.\n");
      printf("Uso: %s clave \"mensaje\"\n", argv[0]);
      exit(1);
   }
   
   char mensaje[1024];
   int clave = atoi(argv[1]);
   
   strcpy(mensaje, argv[2]);
   
   // menú
   
   char opcion = 0;
   
   do{
      printf("1. Cifrar\n");
      printf("2. Descifrar\n\n");
      printf("Elija una opción: ");
      opcion = fgetc(stdin); fgetc(stdin);
      if (opcion <= '0' || opcion > '2')
         printf("Opción incorrecta\n\n");
   }while (opcion <= '0' || opcion > '2');
   
   // cifrar/descifrar
   
   int i;
   
   if (opcion == '1'){

      for (i=0; i<strlen(mensaje); i++){
         if (mensaje[i] != ' ')   // ignoro espacios
            // paso a minúsculas, resto 'a' para trabajar con 0..26, sumo clave
            // aplico módulo longitud alfabeto, sumo 'a' para volver a ascii
            mensaje[i] = ((tolower(mensaje[i]) - 'a' + clave) % 26) + 'a';
      }
      
      printf("\nMensaje cifrado: \"%s\"\n", mensaje);

   }else{

      for (i=0; i<strlen(mensaje); i++){
         if (mensaje[i] != ' '){      // ignoro espacios
            mensaje[i] = tolower(mensaje[i]) - (clave % 26);
            if (mensaje[i] < 'a')
               mensaje[i] += 26;
         }
      }

      printf("\nMensaje descifrado: \"%s\"\n", mensaje);

   }

   return 0;
}
Sin tener el cuenta la parte del menú, y la de desencriptar, esto tendría que mostrar las cadenas invertidas, pero se me cuelga el programa,da error de windows ¿Alguien sabe porqué?

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

char *cadena;
char *inversa;
int longitud;
int i=;/*int=0??*/

int main(void){

printf("Introduce una cadena");
gets (cadena);
longitud=strlen(cadena);

for (i = 0;i < longitud; i++){
    inversa[i]=cadena[longitud-1-i];
    printf("%c",inversa[i]);}
   
    for (i=0;i<longitud;i++){
        printf("%c",cadena[longitud-1-i]);
        }
        }
Por la función gets y la forma en que has definido cadena, debe de ser un array de caracteres y no un puntero a char (char cadena[32], por ejemplo). http://c.conclase.net/librerias/funcion.php?fun=gets

Tras cambiar eso te va a cascar en más sitios.

Cuando te pase eso y no sepas dónde está el error ya que se produce en tiempo de ejecución, en programas sencillos de este tipo y ya que estás aprendiendo puedes ir comentando código para ver qué parte produce el error.

Por cierto, la función gets es mejor no usarla mucho, incluso algunos compiladores avisan, por ejemplo gcc dice: "warning: the `gets' function is dangerous and should not be used."
Ya lo tengo.

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

char cadena[500];
char inversa[500];
int longitud;
int i=0;
int a;

int main(void){
     printf("Pulsa 1 para encriptar o 2 para desencriptar ");
     scanf("%d",&a);
     if(a==1)
     {
     printf("Introduce una cadena: ");
scanf("%s",cadena);
longitud=strlen(cadena);
printf("Tu mensaje encriptado es: ");

for (i = 0;i < longitud; i++){
    inversa[i]=cadena[longitud-1-i];
    printf("%c",inversa[i]);}
   
    for (i=0;i<longitud;i++){
        printf("%c",cadena[longitud]);
         }
       }
       else
       
       if (a==2)
       {
printf("Introduce el mensaje anteriormente encriptado ");
scanf("%s",cadena);
longitud=strlen(cadena);
printf("tu mensaje desencriptado es: ");
                for (i = 0;i < longitud; i++){
    inversa[i]=cadena[longitud-1-i];
    printf("%c",inversa[i]);}
   
    for (i=0;i<longitud;i++){
        printf("%c",cadena[longitud]);
         }
       }
                }


Gracias a todos los que habeis posteado
18 respuestas