IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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 :

printf modifie le comportement


Sujet :

C

  1. #1
    Membre actif Avatar de je®ome
    Inscrit en
    Octobre 2005
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 285
    Points : 225
    Points
    225
    Par défaut printf modifie le comportement
    Bonjour,

    je viens de rencontrer un problème assez bizarre que je n'arrive pas à m'expliquer.
    J'ai écrit un petit programme qui calcule des nombres premiers, mais dépendant du fait que je fasse un printf ou pas, les données renvoyées sont erronnées.

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    int prime_number(int n){
    	int res=1;
    	FILE * f = fopen("prime.log", "r+");
    	if(!f)
    	{
    		fprintf(stderr, "fopen failed\n");
    		exit(EXIT_FAILURE);
    	}
    	char *tmp_number;
    	tmp_number=malloc(100);
    	while((fgets(tmp_number,100,f))!=NULL){
    		int prime;
    		char *tmp;
    		strncpy(tmp,tmp_number,strlen(tmp_number)-1);
    		prime=atoi(tmp);
    		if(n % prime == 0){
    			res=0;
    			break;
    		}
    	}
    	if(res==1)
    	{	
    		sprintf(tmp_number,"%d",n);
    		strcat(tmp_number,"\n");
    		fwrite(tmp_number,1,strlen(tmp_number),f);
    	}
    	fclose(f);
    	return res;
    }
     
    int main()
    {
    	int i=4;
    	int count=2;
    	while(count<100)
    	{
    		printf("test %d\n",i);  // Pas de soucis avec ce printf, mais sans :evilred: 
    		if(prime_number(i)==1)
    			count++;
    		i++;
    	}
    	return 0;
    }
    Avec le printf, le fichier prime.log est correct, par contre sans celui-ci, il y insère des nombres non premiers.
    Le fichier prime.log contient 2 lignes au début.

    prime.log:

    2
    3

    Quelqu'un peut-il m'expliquer comment ceci est possible stp ?
    Le traitement devrait être le même à tous les coups.....
    Wer nicht probiert, verliert !!

  2. #2
    Membre éclairé Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par je®ome
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [...]
    	while((fgets(tmp_number,100,f))!=NULL){
    		int prime;
    		char *tmp;
    		strncpy(tmp,tmp_number,strlen(tmp_number)-1);
    		prime=atoi(tmp);
    		if(n % prime == 0){
    			res=0;
    			break;
    		}
    	}
    [...]
    Avec tmp non initialisé, ton code devrait même crasher....
    Software Failure. Press left mouse button to continue.
    Guru Meditation #0100000C.000FE800

  3. #3
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Points : 17 916
    Points
    17 916
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par je®ome
    Avec le printf, le fichier prime.log est correct, par contre sans celui-ci, il y insère des nombres non premiers.
    CLASSIQUE....

    Indicateur infaillible d'un dépassement de mémoire quelque part...

    Si le fait d'enlever ou d'ajouter un printf ne donne pas la même chose alors écrasement de quelque chose quelque part...
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  4. #4
    Membre actif Avatar de je®ome
    Inscrit en
    Octobre 2005
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 285
    Points : 225
    Points
    225
    Par défaut
    T'as complétement raison, mais ce n'est pas le cas.
    Par contre, le comportement indéterminé dû à cette non-initialisation
    a été enlevé.
    ça marche à présent.

    ça fait quelques mois que je n'ai fait de C.

    Merci pour l'aide rapide et surtout efficace.
    Wer nicht probiert, verliert !!

  5. #5
    Membre actif Avatar de je®ome
    Inscrit en
    Octobre 2005
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 285
    Points : 225
    Points
    225
    Par défaut
    Merci à toi aussi souviron.

    Jvais bientôt avoir honte.....
    Wer nicht probiert, verliert !!

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par souviron34
    CLASSIQUE....

    Indicateur infaillible d'un dépassement de mémoire quelque part...

    Si le fait d'enlever ou d'ajouter un printf ne donne pas la même chose alors écrasement de quelque chose quelque part...
    Non. Tout ce qu'on peut dire, c'est "suspicion de comportement indéterminé". Ne jamais faire d'hypothèses sur les comportements indéterminés. Il sont, par définition, imprévisibles.

    Par contre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
          char *tmp;
          strncpy (tmp, tmp_number, strlen (tmp_number) - 1);
    est clairement un CI comme l'ont fait remarqués Crocodilex et mon compilateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Project   : Forums
    Compiler  : GNU GCC Compiler (called directly)
    Directory : C:\dev\forums\
    --------------------------------------------------------------------------------
    Switching to target: default
    Compiling: main.c
    main.c: In function `prime_number':
    main.c:18: warning: 'tmp' might be used uninitialized in this function
    main.c: At top level:
    main.c:38: warning: function declaration isn't a prototype
    Linking console executable: console.exe
    Process terminated with status 0 (0 minutes, 1 seconds)
    0 errors, 2 warnings
    Pas de Wi-Fi à la maison : CPL

  7. #7
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    Vous vous dites comportement indéterminé, mais chez moi ce genre d'erreur c'est segfault directement Peut être parce que l'utilisation de ram chez moi est toujours à 100% je ne sais pas
    --
    Ooui strcpy n'alloue pas la mémoire. Il faut utiliser strdup dans un cas comme celui là si c'est pour une recopie de chaîne avec allocation dynamique de strlen(chaine_de_depart)+1 octets (en comptant le '\0'), car il permet de s'affranchir de l'utilisation de malloc, mais le buffer alloué n'est pas très pratique parce qu'il est alors impossible d'y loger un caractère en plus.
    ---
    question subsidiaire : le bon conseil 'Don't mixed declaration and code' qui oblige a faire ses déclarations de variables au début du code doit-il être ignoré? pour suivre les allocations au plus près du code?

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 370
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 370
    Points : 41 523
    Points
    41 523
    Par défaut
    Si l'on est certain d'avoir la possibilité de faire ses déclarations au milieu du code partout où l'on compilera (NB: Si l'on ne programme pas en C sous Visual, parce que Visual ne supporte pas C99), alors je dirais que ça vaut mieux pour les variables qui ne sont plus modifiées après initialisation. Ça permet de les déclarer const, et donc de s'assurer qu'elles ne seront pas modifiées par la suite...
    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.

  9. #9
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par kromartien
    Vous vous dites comportement indéterminé, mais chez moi ce genre d'erreur c'est segfault directement Peut être parce que l'utilisation de ram chez moi est toujours à 100% je ne sais pas
    Peut être, mais peux-tu affirmer qu'il n'y a pas de comportements indéterminées sans effets visibles ? Tout le problème est là.

    A encadrer :

    Les tests ne permettent pas de détecter les comportements indéterminés. Seule une connaissance approfondie de la norme et un contrôle visuel du code le permettent.

    C'est pour ça que je dis, persiste et signe "Le C n'est pas un langage de débutant".
    question subsidiaire : le bon conseil 'Don't mixed declaration and code' qui oblige a faire ses déclarations de variables au début du code doit-il être ignoré? pour suivre les allocations au plus près du code?
    Je ne sais pas d'où sort ce 'bon conseil', probablement de gens qui utilisent des langages rigides comme le Pascal...

    Le C permet de définir les variables au plus près des besoins et c'est bien pratique, surtout pour leur donner tout de suite leur bonne valeur.

    Par contre, je n'aime pas que la définition soit ailleurs qu'au début d'un bloc (C99), car je trouve alors la portée peu claire...

    Ca ne me dérange pas, si c'est nécessaire, de créer un bloc supplémentaire pour pouvoir définir une variable.
    Pas de Wi-Fi à la maison : CPL

  10. #10
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    en fait c'est le C90 qui dit ça, l'option -pedantic avertit le programmeur que déclarer des variables dans le code est interdit. Donc j'essaie de ne pas le faire parce que je met toujours l'option -pedantic quand je compile.

  11. #11
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par kromartien
    en fait c'est le C90 qui dit ça, l'option -pedantic avertit le programmeur que déclarer des variables dans le code est interdit. Donc j'essaie de ne pas le faire parce que je met toujorus l'option -pedantic quand je compile.
    Mais même en C90, tu as le droit de définir les variables en début de bloc.
    Pas de Wi-Fi à la maison : CPL

  12. #12
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    bloc exécutable alors, délimité par des accolades, n'importe quel if permet la définition en début de bloc? D'accord merci. Je vais procéder comme cela alors pour restreindre la portée des variables maintenant.

  13. #13
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par kromartien
    bloc exécutable alors, délimité par des accolades, n'importe quel if permet la définition en début de bloc?
    Absolument. Personnellement, je n'hésite pas à créer un bloc si nécessaire...
    Pas de Wi-Fi à la maison : CPL

  14. #14
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par kromartien
    n'importe quel if permet la définition en début de bloc?
    Et pas que les if, c'est vrai pour tout bloc dans le code. Meme pour un bloc non induit pas une structure de controle quelconque

  15. #15
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    oui, c'est ce que j'avais compris, merci beaucoup. Mais pour les blocs dédiés, est-il possible de définir un bloc tel quel même s'il n'est pas encadré par une instruction conditionnelle? Par exemple en plaçant des accolades dans un programme?

  16. #16
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par kromartien
    oui, c'est ce que j'avais compris, merci beaucoup. Mais pour les blocs dédiés, est-il possible de définir un bloc tel quel même s'il n'est pas encadré par une instruction conditionnelle? Par exemple en plaçant des accolades dans un programme?
    Oui.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  17. #17
    Membre éprouvé

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 116
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 116
    Points : 1 111
    Points
    1 111
    Par défaut
    oui je comprends que ça contribue à la lisibilité et à la structuration du code. Merci beaucoup à vous deux.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 13/04/2011, 11h40
  2. Modifier le comportement d'un formulaire
    Par Immothep dans le forum Langage
    Réponses: 4
    Dernier message: 21/06/2007, 15h46
  3. Modifier le comportement d'une fenêtre de choix
    Par Nalmo dans le forum Applets
    Réponses: 1
    Dernier message: 03/11/2006, 10h50
  4. modifier le comportement d'ArrayList
    Par Zorgz dans le forum API standards et tierces
    Réponses: 8
    Dernier message: 09/10/2006, 13h31
  5. [D7] Modifier le comportement d'un FieldKind = fklookup
    Par Débéa dans le forum Bases de données
    Réponses: 4
    Dernier message: 30/01/2006, 12h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo