Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

Décodeur de morse


Sujet :

C

  1. #1
    Candidat au Club
    Décodeur de morse
    Bonjour à tous !

    Je me suis fraichement remis au langage C, et je suis allé faire un challenge sur codewars, qui consiste à décoder du morse donné en input à une fonction. Mais comme vous, vous doutez, je rencontre un problème .

    Le code en question:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    const char *morse[55] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", ".-.-.-", "--..--", "..--..", ".----.", "-.-.--", "-..-.", "-.--.", "-.--.-", ".-...", "---...", "-.-.-.", "-...-", ".-.-.", "-....-", "..--.-", ".-..-.", "...-..-", ".--.-.", "...---..."};  
    const char *ascii[55] = {"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",     "1",     "2",     "3",     "4",     "5",     "6",     "7",     "8",     "9",     ".",      ",",      "?",      "'",      "!",      "/",     "(",     ")",      "&",     ":",      ";",      "=",     "+",     "-",      "_",      "\"",     "$",       "@",      "SOS"};
     
    void decode_morse(char *morse);
    void error_(const char *message);
    int count_array(char *tocount);
     
    int main(int argc, char *argv[])
    {
    	decode_morse(".... . -.--   .--- ..- -.. .");
    	return 1;
    }
     
    void decode_morse(char *morse_)
    {
    	int i, y = 0 ; 
    	char *decoded = strdup(morse_);
     
    	if(decoded)
    	{	
    		int count = count_array(decoded);
    		char *token = strtok(decoded, " ");
    		char *array[count];
    		char ret[count];
     
    		while(token != NULL)
    		{
    			array[i] = token;
    			i++;
    			token = strtok(NULL, " ");	
    		}
     
    		for(i = 0; i < count; i++)
    		{	
    			for(y = 0; i < 55; y++)
    			{
    				if(array[i] == morse[y])
    				{
    					ret[i] = *ascii[y];
    				}
    			}
    		}
    	}	
     
     
    	else
    		error_("Strdup failed");
    }
     
    void error_(const char *message)
    {
    	fprintf(stderr, "%s\r\n", message);
    }
     
    int count_array(char *tocount)
    {
    	char *copy = strdup(tocount);
    	int i = 0;
    	if(copy)
    	{
    		char *token = strtok(copy," ");
    		while(token != NULL)
    		{
    			i++;
    			token = strtok(NULL, " ");
    		}
    		free(copy);
    		return i;
    	}
    	else
    		error_("Function failed");
    }


    ça me renvoit un segfault !
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    epicout@epic:~/code$ gcc -o code coding.c && ./code
    Segmentation fault

    Du coup ni une, ni deux, je fais une compilation avec les infos de débug, et je lance gdb, qui me renvoit à ceci:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    Program received signal SIGSEGV, Segmentation fault.
    0x000055555555537d in decode_morse (morse_=0x55555555570c ".... . -.--   .--- ..- -.. .") at coding.c:32
    32                              array[i] = token;


    étant donné que token est censé renvoyer un pointeur de char, je ne saisis pas où est mon erreur !

    Si vous avez l'aimabilité de me dire ce qui ne va pas dans mon code, et je pense pas qu'il n'y ait qu'une seule chose qui ne va pas, je vous en serais reconnaissant, merci !

  2. #2
    Expert éminent
    Ton code utilise les tableaux à taille variable (VLA) - donc demande du C99.

    Ensuite , il faut refaire ton système d'erreur afin que tous les chemins de la fonction count_array retourne quelque chose.

    Ensuite ton code ne peut pas fonctionner if(array[i] == morse[y]) ne teste qu'1 seul caractère (le + à gauche).
    Hors tous les codes morses ont + d'1 caractère

    Et je pense que ton code n'est pas fini parce que tu remplis la variable locale ret sans l'utiliser et qu'il n'y a aucune erreur en cas de code morse erroné.

    Ensuite pour ton plantage, il y a 2 problèmes
    • Ta variable locale i n'est pas initialisée (ligne 21, int i, y = 0 ;)
    • Ton test de boucle ne porte pas sur le compteur de boucle (ligne 40, for(y = 0; i < 55; y++)

  3. #3
    Candidat au Club
    Mon dieu, que d'erreurs d'innattention, merci à toi, je corrige tout ça, et reviendrais ici si j'ai toujours des soucis, merci à toi !

    EDIT: tout fonctionne à merveille, voici mon code.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    const char *morse[55] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", ".-.-.-", "--..--", "..--..", ".----.", "-.-.--", "-..-.", "-.--.", "-.--.-", ".-...", "---...", "-.-.-.", "-...-", ".-.-.", "-....-", "..--.-", ".-..-.", "...-..-", ".--.-.", "...---..."};  
    const char *ascii[55] = {"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",     "1",     "2",     "3",     "4",     "5",     "6",     "7",     "8",     "9",     ".",      ",",      "?",      "'",      "!",      "/",     "(",     ")",      "&",     ":",      ";",      "=",     "+",     "-",      "_",      "\"",     "$",       "@",      "SOS"};
     
    char * decode_morse(char *morse_);
    void error_(const char *message);
    int count_array(char *tocount);
     
    int main(int argc, char *argv[])
    {
    	char * return_ = decode_morse(".... . -.--   .--- ..- -.. .");
    	fprintf(stdout,"%s", return_);
    	return 1;
    }
     
    char * decode_morse(char *morse_)
    {
    	int i= 0;
    	int y = 0 ; 
    	char *decoded = strdup(morse_);
     
    	if(decoded)
    	{	
    		int count = count_array(decoded);
    		char *token = strtok(decoded, " ");
    		char *array[count];
    		char *ret = malloc(sizeof(char) * count);
     
    		while(token != NULL)
    		{
    			array[i] = token;
    			i++;
    			token = strtok(NULL, " ");	
    		}
     
    		for(i = 0; i < count; i++)
    		{	
    			for(y = 0; y < 55; y++)
    			{
    				if(strcmp(array[i], morse[y]) == 0)
    				{
    					ret[i] = *ascii[y];
    				}
    			}
    		}
     
    		return ret;
    	}	
     
     
    	else
    		error_("Strdup failed");
    }
     
    void error_(const char *message)
    {
    	fprintf(stderr, "%s\r\n", message);
    }
     
    int count_array(char *tocount)
    {
    	char *copy = strdup(tocount);
    	int i = 0;
    	if(copy)
    	{
    		char *token = strtok(copy," ");
    		while(token != NULL)
    		{
    			i++;
    			token = strtok(NULL, " ");
    		}
    		free(copy);
    		return i;
    	}
    	else
    		error_("Function failed");
    }

  4. #4
    Expert éminent sénior
    Bonjour
    Citation Envoyé par EpicOut Voir le message
    EDIT: tout fonctionne à merveille, voici mon code.
    A merveille faut le dire vite. Dans ta fonction decode_morse(), tu fais deux allocations mémoires qui ne sont jamais libérées. Il m'a suffit de remplacer ton main() par celui-ci...
    Code c :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(int argc, char *argv[]) {
    	size_t i;
    	char *return_;
    	for (i=0; i < 100000000; i++) return_ = decode_morse(".... . -.--   .--- ..- -.. .");
    	fprintf(stdout,"%s", return_);
    	return 1;
    }

    ... et ça a planté mon ordi.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  5. #5
    Expert éminent sénior
    Planté ton ordi? Quel genre d'ordinateur plante au lieu de simplement refuser l'allocation mémoire? Un système embarqué? Un Linux avec Overcommit?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Expert éminent sénior
    Citation Envoyé par Médinoc Voir le message
    Planté ton ordi? Quel genre d'ordinateur plante au lieu de simplement refuser l'allocation mémoire? Un système embarqué? Un Linux avec Overcommit?
    Oui, désolé, j'ai exagéré mes propos. Le processus s'est simplement arrêté avec un message "processus arrêté". Ceci dit, ce n'est pas un simple refus d'alloc, c'est un vrai UB puisque la zone "non allouée" est quand-même utilisée ensuite (sans compter le VLA qui n'arrange rien). Et donc un UB peut très bien planter un ordi...
    Accessoirement c'était un ordi virtuel avec disque système immuable donc pas de perte réelle.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  7. #7
    Membre éprouvé
    Hello,

    De toute façon, ce programme est destiné à se planter: il affiche return_ dans le main(), qui est la variable ret dans decode_morse() (allouée par malloc()), mais qui ne se termine pas par un \0

  8. #8
    Expert éminent sénior
    Citation Envoyé par edgarjacobs Voir le message
    mais qui ne se termine pas par un \0
    Bien vu, j'avais pas fait attention
    Attention toutefois, tu ne peux pas dire "destiné à se planter" car là tu fais une prédiction sur un UB qui est, par définition, imprévisible. Mais c'était bien vu tout de même
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

###raw>template_hook.ano_emploi###