[C] Je ne comprend pas mon erreur

Bonjour.
Alors, voilà, j’ai un petit souci dans ce bout de code :

void initialise(char motSecret[], char motAffiche[]) { int i = 0, longueur = 0; // variable de parcours, longueur du mot longueur = strlen(motSecret); motAffiche = malloc(longueur * sizeof(char)); if (motAffiche == NULL) { exit (EXIT_FAILURE) ; } for (i = 0; i < longueur; i++) { motAffiche[i] = '*' ; } }
Ce que je veux faire, c’est compter le nombre de caracteres dans motSecret[] puis mettre autant de * dans motAffiche[] . Comme je ne suis pas censé connaitre à l’avance la taille de motSecret[], j’utilise un malloc.
Mon souci est que, dans la fonction, motAffiche est bien transformé en “******”, mais pas dans ma fonction main.
Comme quoi, je croyais avoir compris les pointeurs…
Bref, je ne vois pas où est mon erreur, car j’ai déja modifié un tableau de cette façon, même s’il ne s’agissait que de nombres, pas d’une chaine.
Une correction svp?

malloc renvoie un entier non ? et tu définie MotAffiche comme un char, rien que la tu te fais jeter :wink:

C’est pas faux… mais comment puis-je créer mon tableau de char alors?

l’erreur ne vient pas de là. Tu peux caster ce que te renvoie malloc en char * pour être plus “propre” mais ça ne chanegra pas.

C’est en effet une erreur de pointeur : tu lui passes un pointeur pour “motAffiche”. Or, tu va modifier ce pointeur (tu lui affectes une valeur avec malloc !). Il faut donc utiliser… un pointeur de pointeur ^^

Je me mélange… il faut que j’utilise un pointeur de pointeur comme argument de la fonction?

Yep,

Si tu veux modifier un int dans ta fonction, tu lui passe un int*. Bah là c’est pareil, tu veux modifier un char*, donc tu lui passe un char** :stuck_out_tongue:

Si tu ne voulais modifier que le contenu du char*, lui passer char* suffisait.

J’ai fait ceci :

void initialise(char motSecret[], char** motAffiche) { int i = 0, longueur = 0; // variable de parcours, longueur du mot longueur = strlen(motSecret); motAffiche = malloc(longueur * sizeof(char)); if (motAffiche == NULL) { exit (EXIT_FAILURE) ; } for (i = 0; i < longueur ; i++) { *motAffiche[i] = '*' ; } }
Mais j’ai une erreur de segmentation. La fonction ne s’exécute même pas. Le souci ne vient-il pas du fait que je passe à la fonction un pointeur de pointeur qui est vide? Car comme je fais un malloc que dans la fonction, avant, mon pointeur vaut NULL.

Ton code a deux erreurs :

  1. Tu ne fais pas le malloc là où il faut :

Il faut faire :

  1. Attention à la priorités des opérateurs ! Il ne faut pas écrire :

mais :

Vala vala ^^"

La première erreur, je l’avais corrigé quelques minutes ensuite. Pour le tableau, par contre, j’ignorais la syntaxe. Bon, je reteste tout ça. Merci encore!

J’ai toujours une erreur de segmentation… :frowning:
Voici le code entier. Que fais-je de mal?


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

void demandeMotSecret(char motSecret[]);
int jeu(char motSecret[], char motAffiche[]);
char lireCaractere();
void viderBuffer();
void initialise(char motSecret[], char** motAffiche);	


int main(int argc, char** argv)
{
	int resultat = 0, compteur = 10, cont = 1;
	char motSecret[100] = {0};
	char *motAffiche = NULL;

	printf("Bienvenue dans le pendu \n \n"); //message d'accueil

	while (cont == 1) //boucle principale
	{
		demandeMotSecret(motSecret); //fonction pour définir le mot secret
		initialise(motSecret, &motAffiche);	
		while (resultat != 1 && compteur >= 0)
		{
			printf("Il vous reste %d coups à jouer\n", compteur), 
			resultat = jeu(motSecret, motAffiche); // Cette fonction renvoie 1 si gagné, 0 sinon
			compteur = compteur - 1;
		}
		if (resultat == 1)
		{
			printf("Bravo, tu as gagné!\n\n");
		}
		else
		{
			printf("Bouh, tu as perdu! :P \n\n");
		}
		//là, le jeu est fini, on propose une autre partie
		printf("Voulez-vous rejouer? \n");
		printf("1. Oui\n2. Non\n");
		scanf("%d", &cont);
		printf("%d", cont);
	}

		free(motAffiche);	
		return EXIT_SUCCESS;
}

char lireCaractere()
{
	 
    char caractere = 0;
 
    caractere = getchar(); // On lit le premier caractère
    caractere = toupper(caractere); // On met la lettre en majuscule si elle ne l'est pas déjà
 
    // On lit les autres caractères mémorisés un à un jusqu'à l'\n (pour les effacer) 
    while (getchar() != '\n') ;
 
    return caractere; // On retourne le premier caractère qu'on a lu
	
}
void viderBuffer()
{
	int c = 0;
	while (c != '\n' && c != EOF)
	{
		c = getchar();
	}
}
void demandeMotSecret(char motSecret[])
{
	char *entree = NULL;
	int i = 0;
	
	printf("Donnez le mot secret\n");
	fgets(motSecret, 100, stdin);
	entree = strchr(motSecret, '\n');
    if (entree != NULL) // on remplace le retour à la ligne
    {
	*entree = '\0';
    }
    //viderBuffer();
    for (i = 0; i < (strlen(motSecret)); i++)
    {
	    motSecret[i] = toupper(motSecret[i]);
    }
}
	
int jeu(char motSecret[], char motAffiche[])
{
	char lettre = 0;
	int j = 0;
	printf("Quel est le mot secret? %s\n", motAffiche);
	printf("Proposez une lettre : ");
	lettre = lireCaractere();
	for ( j = 0; j < (strlen(motSecret)); j++)
	{
		if ( motSecret[j] == lettre )
		{
			motAffiche[j] = lettre;
		}
	}
	if ( (strcmp(motAffiche, motSecret)) == 0 )
	{
		return 1;
	}
	else
	{
		return 0;
	}
	
}
void initialise(char motSecret[], char** motAffiche)
{
	int i = 0, longueur = 0;
	longueur = strlen(motSecret);
	*motAffiche=malloc(longueur * sizeof(char));

	for (i = 0; i < longueur ; i++)
	{
		*(motAffiche)[i] = '*' ;
	}
}

Avec le message d’erreur ça serait mieux :wink:

Je n’ai aucune erreur à la compilation, juste à l’éxécution, juste après avoir rentré le “motsecret” :
Erreur de segmentation .
Donc pas grand chose à dire.

(Note : J’ai pas encore regardé ton code)

Une segfault il y a jamais de messages en plus. C’est bien pour ça que beaucoup de gens préfèrent ne pas gérer la mémoire ou se prendre un NullPointerException en Java.

Quand tu as un segfault, pour essayer de debuguer tu peut utiliser un debuguer (gdb est très bien sur tout si tu code avec emacs). Tu peut aussi voir certaines choses avec strace qui te montre tout les appels systèmes. Enfin tu peut aussi utiliser memcheck (qui fait parti de valgrind).

Quand tu a un segfault c’est que tu as un problème de mémoire (tu accède à un endroit que t’a pas le droit). Les cas classiques :
[ul]
[li]utilisation d’un pointeur null ou non initialisé (gcc les initialise à 0 mais ce n’est pas dans la norme)[/li]
[li]dépassement de la taille d’un tableau[/li]
[li]utilisation d’un pointeur après libération de la mémoire[/li]
[li]se planter dans une série de pointeur (pointeur de pointeur de pointeur…, structure de données)[/li][/ul]

Voila j’ai pas le temps de regarder ton code mais je t’ai donné des pistes :slight_smile:

Bah une segfault, le message d’erreur n’est jamais explicite hein !

En fait il fallait lire :

Désolé :stuck_out_tongue:

Par contre après il a encore d’autres erreurs de pointeurs ^^"

Pour vérifier plus ou moins facilement les pointeurs, perso je passe par valgrind (ou gdb).

Faut compiler ses sources avec l’option -g (active les traces de debug) et lancer le programme avec

Et pouf ça dit où et pourquoi ça plante :smiley:

[code]Bienvenue dans le pendu

Donnez le mot secret
toto
==6659== Invalid write of size 1
==6659== at 0x400BA5: initialise (test.c:122)
==6659== by 0x4008BB: main (test.c:23)
==6659== Address 0x4f544f54 is not stack’d, malloc’d or (recently) free’d
[/code]

Eh bien, merci pour toutes ces pistes! De 1, l’option -g m’était totalement inconnue aussi, et valgrind sera sûrement bien pratique à l’avenir.
J’ai simplement corrigé le
*(motAffiche)[i]
par
(*motAffiche)[i]
et tout roule à merveille désormais. Je suis un peu rassuré, j’ai eu peur d’avoir réellement rien compris aux pointeurs. De plus, je ne m’étais pas encore mis dans la tête le véritable fonctionnement de malloc.

En somme,

for (i = 0; i < 1000; i++) { printf("merci! \n"); } :smiley:

Et d’ailleurs, mon code était faux (enfin, si on suit la regle du pendu)

[code]// pendu.c
//
// Copyright 2010 veronique veronique@super-albert
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
// MA 02110-1301, USA.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void demandeMotSecret(char motSecret[]);
int jeu(char motSecret[], char motAffiche[]);
char lireCaractere();
void viderBuffer();
void initialise(char motSecret[], char** motAffiche);

int main(int argc, char** argv)
{
int resultat = 0, compteur = 10, cont = 1;
char motSecret[100] = {0};
char *motAffiche = NULL;

printf("Bienvenue dans le pendu \n \n"); //message d'accueil

while (cont == 1) //boucle principale
{
	demandeMotSecret(motSecret); //fonction pour définir le mot secret
	initialise(motSecret, &motAffiche);	
	while ( (strcmp(motAffiche, motSecret)) != 0 && compteur >= 0)
	{
		printf("Il vous reste %d coups à jouer\n", compteur), 
		resultat = jeu(motSecret, motAffiche); // Cette fonction renvoie 1 si gagné, 0 sinon
		if (resultat == 0)
		{
		compteur = compteur - 1;
		}
	}
	if ( (strcmp(motAffiche, motSecret)) == 0 )
	{
		printf("Bravo, tu as gagné!\n\n");
	}
	else
	{
		printf("Bouh, tu as perdu! :P \n\n");
	}
	//là, le jeu est fini, on propose une autre partie
	printf("Voulez-vous rejouer? \n");
	printf("1. Oui\n2. Non\n");
	scanf("%d", &cont);
	printf("%d", cont);
}

	free(motAffiche);	
	return EXIT_SUCCESS;

}

char lireCaractere()
{

char caractere = 0;

caractere = getchar(); // On lit le premier caractère
caractere = toupper(caractere); // On met la lettre en majuscule si elle ne l'est pas déjà

// On lit les autres caractères mémorisés un à un jusqu'à l'\n (pour les effacer) 
while (getchar() != '\n') ;

return caractere; // On retourne le premier caractère qu'on a lu

}
void viderBuffer()
{
int c = 0;
while (c != ‘\n’ && c != EOF)
{
c = getchar();
}
}
void demandeMotSecret(char motSecret[])
{
char *entree = NULL;
int i = 0;

printf("Donnez le mot secret\n");
fgets(motSecret, 100, stdin);
entree = strchr(motSecret, '\n');
if (entree != NULL) // on remplace le retour à la ligne
{
*entree = '\0';
}
//viderBuffer();
for (i = 0; i < (strlen(motSecret)); i++)
{
    motSecret[i] = toupper(motSecret[i]);
}

}

int jeu(char motSecret[], char motAffiche[])
{
char lettre = 0;
int j = 0, score = 0;
printf(“Quel est le mot secret? %s\n”, motAffiche);
printf("Proposez une lettre : ");
lettre = lireCaractere();
for ( j = 0; j < (strlen(motSecret)); j++)
{
if ( motSecret[j] == lettre )
{
motAffiche[j] = lettre;
score = 1;
}
}

	return score;

}
void initialise(char motSecret[], char** motAffiche)
{
int i = 0, longueur = 0;
longueur = strlen(motSecret);
*motAffiche=malloc((longueur + 1) * sizeof(char));

for (i = 0; i < longueur ; i++)
{
	(*motAffiche)[i] = '*' ;
}

}
[/code]