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 :

Sortie différente sur while et for identiques


Sujet :

C

  1. #1
    Invité
    Invité(e)
    Par défaut Sortie différente sur while et for identiques
    Bonjour,
    Sur ce 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
    #include <stdio.h>
     
    int main(){
     
            char value[11] ="OH1B2RT56U";
    	char ref[5] ="abcd";
    	char new[40][3];
    	int i =0, j =0, k =0, l =0;
     
    	while(ref[i] !='\0'){
     
    		while(value[j] !='\0'){
     
    			new[k][l] =value[j];
    			l++;
    			new[k][l] =ref[i];
    			l =0;
    			printf("%s ",new[k]);
    			k++, j++;
    		}
    		j =0;
    		i++;
    	}
    	printf("\n");
     
    	k =0, l =0;
     
    	for(int i =0; ref[i] !='\0'; i++){
     
    		for(int j =0; value[j] !='\0'; j++){
     
    			new[k][l] =value[j];
    			l++;
    			new[k][l] =ref[i];
    			l =0;
    			printf("%s ",new[k]);
    		}
    	}
     
    	return (0);
    }
    Les deux boucles font la même chose, mais à la sortie la boucle while tourne free style et n'affiche jamais les mêmes signes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Oa Ha 1a Ba 2a Ra Ta 5a 6a Ua Ob Hb 1b Bb 2b Rb Tbԇ�U 5bU 6b��� Ub Oc Hc 1c Bc 2c�U� Rc Tc��U� 5cU� 6c Uc�ԇ�U Od�U Hd 1dgl� Bd 2dP�ԇ�U Rd��U Td 5d 6d Ud 
    Oa Ha 1a Ba 2a Ra Ta 5a 6a Ua Ob Hb 1b Bb 2b Rb Tb 5b 6b Ub Oc Hc 1c Bc 2c Rc Tc 5c 6c Uc Od Hd 1d Bd 2d Rd Td 5d 6d Ud
    Quelqu'un, peut-il me dire pourquoi ?

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 668
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 668
    Points : 10 669
    Points
    10 669
    Par défaut
    Non les 2 boucles ne sont pas identiques

    k++


    En réalité ton code est trop mauvais
    • La variable l ne sert à rien, et pire c'est n'importe quoi les ++/ =0 et tu oublies le caractère sentinel '\0' pour chaque duo de lettres
    • Tu n'as pas besoin de redéfinir les variables i et j (dans les boucles for)
    • il manque la gestion de la variable k


    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
    int main(){
        char value[11] = "OH1B2RT56U"; // or char value[] = "OH1B2RT56U";
        char ref[5]    = "abcd"; // or char ref[] = "abcd";
        char new[40][3];
        int i=0, j=0, k=0;
     
        while(ref[i] !='\0'){
            while(value[j] !='\0'){
                new[k][0] = value[j];
                new[k][1] = ref[i];
                new[k][2] = '\0';
     
                printf("%s ", new[k]);
     
                ++k; ++j;
            }
            j=0; ++i;
        }
        printf("\n");
     
        k=0;
     
        for(i=0; ref[i] !='\0'; ++i){
            for(j=0; value[j] !='\0'; ++j, ++k){
                new[k][0] = value[j];
                new[k][1] = ref[i];
                new[k][2] = '\0';
     
                printf("%s ", new[k]);
            }
        }
     
        return (0);
    }

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par MissLoop Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    			new[k][l] =value[j];
    			l++;
    			new[k][l] =ref[i];
    			l =0;
    			printf("%s ",new[k]);
    Quelqu'un, peut-il me dire pourquoi ?
    Tu ne peux pas demander à afficher via "%s" un tableau de char dans lequel il n'y a pas de '\0', ce n'est pas une string. Donc tu obtiens n'importe quoi et c'est tout à fait normal.

  4. #4
    Invité
    Invité(e)
    Par défaut
    @ foetus
    Non les 2 boucles ne sont pas identiques
    Oui, oui je me suis trompée.
    D'ailleurs, si j'avais rempli le tableau de la boucle for, j'aurais constaté le même résultat.

    Tu n'as pas besoin de redéfinir les variables i et j (dans les boucles for)
    Merci pour cette remarque.

    ... et pire c'est n'importe quoi les ++/ =0...
    Lopo compris...
    Veux-tu dire qu'il y a trop de ++ et que l'affectation à 0 est redondante ?

    Dans tous les cas merci pour ta remarquable réponse.
    Joyeux Noël.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Salut Sve@r, j'espère que tu vas bien.
    J'explore le C en ce moment et je rame quelque peu, mais c'est assez passionnant.

    Pour en revenir au "stop" ou plus précisément à la "fin de section" que représente '\0', je pensais que dans tous les cas le caractère de fin était géré automatiquement.
    De plus, j'ai décrété qu'un tableau de char à 2 dimensions devait gérer ses éléments char ensemble comme une string. Et ta judicieuse remarque :
    Tu ne peux pas demander à afficher via "%s" un tableau de char dans lequel il n'y a pas de '\0', ce n'est pas une string.
    Trouve tout son sens lorsque je troque mon :
    Contre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    write(1, &new[k], 2);
    write(1, " ", 1);
    Qui renvoie le bon affichage.
    Merci beaucoup pour ta réponse en te souhaitant d'excellentes fêtes de fin d'année, heureuse d'échanger à nouveau.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 668
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 668
    Points : 10 669
    Points
    10 669
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    lopo compris...
    Veux-tu dire qu'il y a trop de ++ et que l'affectation à 0 est redondante ?
    @Sve@r a également répondu sur cette partie

    Tu as 1 tableau à 2 dimensions, certes, mais c'est plutôt 1 tableau de chaînes de caractères (de 2 caractères puisqu'on ne compte pas le caractère sentinel '\0')

    Donc pour remplir tes chaînes de 2 caractères, tu initialises ta variable l à 0 pour affecter le premier caractère et ensuite tu l'incrémentes de 1 l++ pour affecter le deuxième caractère, et ainsi de suite (lignes 15, 17, 33, 35)
    Et c'est n'importe quoi regarde mon code : tu as juste à affecter les caractères normalement avec les index (new[k][0] = value[j]; new[k][1] = ref[i]; new[k][2] = '\0';)

    Et non le caractère sentinel '\0' n'est pas géré automatiquement c'est à toi de le mettre (regarde mon code, tu le mets dans la dernière case)
    Si tu ne veux pas te prendre la tête avec '\0', il faut initialiser ton tableau au début soit :
    • avec memset(new, 0, (40 * 3 /* * sizeof(char) */));, memset documentation en anglais
    • à la définition char new[40][3] = {0}; (<- note le {0}), mais pas sûr que cela fonctionne dans tous les cas, il faut vérifier

    Au passage oui, le caractère '\0' équivaut à 0.

  7. #7
    Invité
    Invité(e)
    Par défaut
    Ok c'est plus clair.
    Merci pour les moyens de contourner la gestion du caractère '\0', j'va potasser.

  8. #8
    Membre expérimenté Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    652
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 652
    Points : 1 669
    Points
    1 669
    Par défaut
    Citation Envoyé par foetus Voir le message
    • à la définition char new[40][3] = {0}; (<- note le {0}), mais pas sûr que cela fonctionne dans tous les cas, il faut vérifier
    Si le compilateur respecte la norme (ce qui est, à ma connaissance limitée, toujours le cas), c'est garanti par §6.7.9.21 (norme c11)

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Pour en revenir au "stop" ou plus précisément à la "fin de section" que représente '\0
    En C, le type "string" tel qu'on l'entend dans les autres langages (une chaine manipulable, copiable, testable) n'existe pas. Donc il a fallu trouver un truc: et ce truc ça a été que ce serait un tableau de char. Un tableau en C étant toujours (garanti par la norme) contigü en mémoire, il suffit d'avoir la première case pour avoir tout le tableau.
    Mais il n'y a pas de système en C permettant de connaitre la taille d'un tableau. C'est le programmeur qui crée son tableau qui connait sa taille et donc qui le gère. Mais comment faire pour une chaine? Comment savoir où elle se termine? Il a donc été convenu qu'on lui rajouterait un caractère particulier "en plus" valant 0x00 qu'on peut aussi noter '\0' (ce qu'on fait en général pour garder la notation "char")

    Citation Envoyé par MissLoop Voir le message
    , je pensais que dans tous les cas le caractère de fin était géré automatiquement.
    Il faut préciser ce que tu entends par "géré". Si tu crées une fonction qui par exemple compte les caractères d'un chaine, toi tu sais que si on passe une vraie chaine à ta fonction, elle se terminera par '\0' puisque c'est la convention et que si l'appelant ne la respecte pas, son code ne peut pas fonctionner. Donc de fait tu coderas ta fonction pour chercher ce '\0' et arrêter là le comptage. De fait, toutes les fonctions qui reçoivent une chaine pour la traiter feront la même chose (principe des conventions: on les respecte). Donc de ce point de vue là, les fonctions gèrent effectivement ce '\0' sous réserve qu'il y soit.
    Si maintenant tu crées une fonction qui remplit (crée, copie ou tout autre verbe impliquant la notion de création) une chaine, tu sais que pour que ta fonction soit acceptée il faudra qu'elle positionne ce '\0' sinon ta fonction ne respecte pas la convention et reste inutilisable par les autres. De fait, toutes les fonctions de création de strings garantissent qu'elles te donneront en sortie un tableau de char contenant ce '\0' (sauf sur 2 fonctions strncpy et strncat mais on ne va pas en parler immédiatement). Donc de ce point de vue là, les fonctions de création de strings garantissent la présence du '\0' et on peut alors dire qu'elles le gèrent correctement.

    Mais quand toi tu crées une string manuellement, caractère par caractère, le compilo ne sait pas que tu veux créer une string. Lui, tout ce qu'il voit, c'est un remplissage de tableau. Donc si tu veux que ce tableau soit considéré comme string il te faut mettre ce '\0'.
    Seule et unique exception: quand tu déclares ta string, tu peux écrire char s[]="hello". Là le compilateur t'offre un petit cadeau et se charge lui de mettre le '\0'. Ce qui revient à écrire char s[]={'h', 'e', 'l', 'l', 'o', '\0'}.
    Donc non, le caractère de fin n'est pas géré automatiquement, il est juste géré par tous les programmeurs et contributeurs qui t'offrent des fonctions de traitement de chaine déjà toutes faites. Mais si toi tu veux te mettre à créer ta chaine, tu dois alors, comme les autres, faire le job en entier. Et surtout n'oublie jamais toi de le prendre en considération quand tu réfléchis à la taille de ta chaine. Bref si tu écris char s[5] ça veut dire que ta chaine ne pourra contenir que 4 caractères dits "utiles" car la 5° position sera prise par le '\0'. D'ailleurs généralement on écrit plutôt char s[4+1] pour bien montrer aux autres lecteurs qu'on a bien pensé au '\0'.

  10. #10
    Invité
    Invité(e)
    Par défaut
    Tu as démêlé une pelote cérébrale que je me réservais pour me tricoter un bonnet bien chaud, histoire de garder à bonne température ma pauvre boîte crânienne, bien joué !

    Je n'avais ABSOLUMENT pas compris qu'en C le type string n'existait simplement pas. J'ai bien remarqué que ce type était absent, mais je pensais qu'il se substituait grâce au type char et qu'il se manipulait en nombre avec les tableaux à deux dimensions ; vu l'ancienneté du langage, sa gestion exclusivement numérique et surtout sa proximité processeur (après le C, on nage ou pas, enfin, on essaye sûrement de survivre... dans l'océan du langage machine).

    Mais il n'y a pas de système en C permettant de connaitre la taille d'un tableau.
    Et donc le programmeur peut utiliser sizeof() pour gérer un tableau rempli par un utilisateur.

    Il faut préciser ce que tu entends par "géré".
    Je pensais qu'il suffisait de définir le nombre de caractère comprenant '\0' pour que dans tous les cas le compilo comprenne qu'il s'agit de traiter une string...

    Seule et unique exception: quand tu déclares ta string, tu peux écrire char s[]="hello". Là le compilateur t'offre un petit cadeau et se charge lui de mettre le '\0'. Ce qui revient à écrire char s[]={'h', 'e', 'l', 'l', 'o', '\0'}.
    ...puisqu'il était capable de lire un tableau de char comme une string en inscrivant himself le end of the road qui va bien ; en lui offrant en plus la taille +1 de ma string (je veux dire de ma suite de char), je me suis dit qu'il serait indulgent, reconnaissant et pourquoi pas complètement satisfait d'avoir à faire à quelqu'un de consciencieux... mais je m'égare...

    Mais si toi tu veux te mettre à créer ta chaine, tu dois alors, comme les autres, faire le job en entier.
    ...ceci dit si j'avais compris, j'aurais fait le job en entier.

    D'ailleurs généralement on écrit plutôt char s[4+1] pour bien montrer aux autres lecteurs qu'on a bien pensé au '\0'.
    Aux autres lecteurs certes, mais beaucoup à soi-même.
    MER............CI!

  11. #11
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 668
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 668
    Points : 10 669
    Points
    10 669
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Et donc le programmeur peut utiliser sizeof() pour gérer un tableau rempli par un utilisateur.
    Oui et non il faut mieux utiliser strlen pour connaître la taille de ta chaîne de caractères.

    sizeof a 1 comportement spécial avec les tableaux Pour connaître la taille, tu peux faire sizeof(tab) / sizeof(tab[0]) (tu divises la taille octet du tableau par la taille octet du premier élément. En C, tu ne peux pas faire de tableaux multi types sauf pointeur et ils sont contiguës en mémoire)
    Mais le tableau est dégradé en pointeur assez rapidement lors des passages de paramètres (il faut rester dans l'unité de compilation en théorie) : et sizeof( ptr ) c'est soit 4 (en 32 bits) soit 8 (en 64 bits).


    Citation Envoyé par MissLoop Voir le message
    Je pensais qu'il suffisait de définir le nombre de caractère comprenant '\0' pour que dans tous les cas le compilo comprenne qu'il s'agit de traiter une string...
    Le compilateur ne prend que les caractères, et le caractère sentinelle '\0' est + 1 norme convention prise par la bibliothèque standard.
    Rien ne t'empêche de mettre 0xFF (puisqu'en ASCII tu n'as que 127 caractères, 7 bits) ... mais tu ne peux plus alors utiliser la bibliothèque standard : strlen, strcmp, ...

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Et donc le programmeur peut utiliser sizeof() pour gérer un tableau rempli par un utilisateur. tab
    Hélas non, mille fois non, c'est là un gros piège !!!
    Effectivement si au départ tu as un tableau, style float tab[10] (je fais exprès de pas prendre char pour être le plus généraliste possible), tu peux connaitre la taille via sizeof(tab). Ca te répondra "40" (10 éléments de 4 octets). Jusque là, tout va bien.
    Puis admettons que tu passes ce tableau à une fonction "toto()" qui va s'en servir pour faire X, Y, Z. Tu appelles donc toto(tab). Et c'est très très exactement à ce moment là que tout l'échafaudage basé sur sizeof() part en sucette...

    Parce que maintenant, nous nous trouvons dans la fonction toto(). Et celle-ci ne reçoit pas vraiment le tableau en paramètre, juste l'adresse de son premier élément. D'une part parce que comme tous les éléments du tableau sont contigus, avec simplement le premier tu peux ensuite passer au second puis au 3° et etc ; et d'autre part parce que les paramètres sont passés par copie aux fonctions et que pour la rapidité, il vaut mieux copier une adresse (un nombre) que 40 octets (ou 400 ou 4000 si tu avais un tab[100] ou tab[1000]).
    Donc la fonction ne reçoit qu'une adresse qu'elle stocke dans un pointeur (type dédié à stocker les adresses). Donc tu déclares ta fonction ainsi: void toto(float* pt).
    Ensuite, comme les pointeurs sont d'une certaine façon assimilables à des tableaux (attention, juste pour les tableaux simples), dans la fonction tu peux adresser les éléments comme si c'étaient des tableaux. Donc par exemple afficher pt[0], récupérer pt[1], modifier pt[2] etc, toutes ces opérations s'appliquant par ricochet au tableau "tab" du début.
    Sauf que "pt" reste malgré tout un pointeur (donc ne contient en tout et pour tout juste une simple adresse). Donc s'il te prend l'envie d'appeler sizeof(pt) espérant récupérer sa taille 40, tu obtiendras en réalité 8 (la taille d'une adresse en architecture 64 bits).
    Donc non, sizeof() ne peut pas t'aider, il peut seulement t'en donner l'illusion, illusion qui finit un jour ou l'autre par t'exploser au visage. Donc non, tu as un tableau de 10 éléments, à toi de gérer et de ne pas oublier que tu en as 10 car aucun mécanisme du C ne pourra te le rappeler à ta place. Et à ne pas oublier, dans cette gestion, la place nécessaire au '\0" quand le tableau que tu dois manipuler a pour objectif d'être utilisé comme string.

    Citation Envoyé par MissLoop Voir le message
    Je pensais qu'il suffisait de définir le nombre de caractère comprenant '\0' pour que dans tous les cas le compilo comprenne qu'il s'agit de traiter une string...
    Tu es en train de dire que le compilateur, voyant que tu remplis une string, doit alors placer lui-même ce '\0'. Déjà il faudrait qu'il comprenne quand le mettre ce '\0'. Et quand le mettre? En fin de boucle? En fin de fonction? Et dans ce cas si on quitte la fonctions avant la fin? Donc déjà là ça part mal...

    Donc en réalité non, le compilateur ne "comprend pas", ne cherche pas à comprendre. Le '\0' est juste une convention, pas une norme. Le compilo ne fait donc à son sujet aucune supposition, aucune analyse, aucune hypothèse(*). Son rôle est de vérifier la syntaxe puis de convertir le code C en code assembleur. Il traite juste des octets et des instructions sans présumer de leur but. Que tu demandes à placer un '\0' ou un 'x' pour lui c'est la même chose.

    (*) En fait les compilateurs récents peuvent parfois faire des hypothèses pour optimiser certaines boucles. Mais déjà il faut le demander à la compilation (options -O2 et/ou -O3) et d'autre part ce sont des hypothèses basées sur des heuristiques mathématiques ou sur le typage (si par exemple tu es en unsigned, ta variable ne pouvant jamais être négative lui permettra certains raccourcis), pas des hypothèses sur le but du programmeur qui place un '\0' dans un tableau de char

  13. #13
    Invité
    Invité(e)
    Par défaut
    J'ai fait quelques tests sur mon tableau à 2 dimensions le but étant de trouver un moyen de connaître avant manipulation(s) éventuelle(s) sa taille en mémoire et en éléments :
    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
    int main(){
     
    	/////////////////////////////////////////////////////////
    	char basDeCase	 [4+1]		="abcd";
    	char capitale	 [10+1]		="ABCDEFGHIJ";
    	char couple	 	 [39][2+1];
    	int i, j, k=0;
    	for(i=0; basDeCase[i]!='\0'; i++){
    		for(j=0; capitale[j]!='\0'; j++, k++){
    			couple	[k][0]= capitale[j];
    			couple	[k][1]= basDeCase[i];
    			couple	[k][2]= '\0';
     
    		}
    	}
    	/////////////////////////////////////////////////////////
    		for(i=0; i<=39; i++){
    			if(i == 39){
    				printf("%s", couple[i]);
    			}
    			else{
    				printf("%s ", couple[i]);
    			}
    		}
    	/////////////////////////////////////////////////////////
    		printf("\n");
    		printf("couple contient %d caractères avec strlen().\n",strlen(couple));
    		printf("couple contient %d caractères avec sizeof().\n",sizeof(couple));
    		size_t e = sizeof(couple)/sizeof(couple[0]);
    		printf("couple contient %d pseudo-string avec avec sizeof()/sizeof().\n",e);
    		size_t f = sizeof(couple)/sizeof(couple[0]);
    		int a=0;
    			for(i=0; i<=f; i++){
    				a = a + strlen(couple[i]);
    				}
    			printf("couple contient %d caractères en tout avec strlen() en comptant chaque élément par itération.\n", a);
    			printf("\n");
    	/////////////////////////////////////////////////////////
    	return(0);
    }
    Ce qui nous donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Aa Ba Ca Da Ea Fa Ga Ha Ia Ja Ab Bb Cb Db Eb Fb Gb Hb Ib Jb Ac Bc Cc Dc Ec Fc Gc Hc Ic Jc Ad Bd Cd Dd Ed Fd Gd Hd Id Jd
    couple contient 2 caractères avec strlen().
    couple contient 117 caractères avec sizeof().
    couple contient 39 pseudo-string avec avec sizeof()/sizeof().
    couple contient 80 caractères en tout avec strlen() en comptant chaque élément par itération.
    So, strlen() répond bien en nombre d'éléments pseudo-string et char par contre en mémoire il manque 3 octets... Et il n'en manque plus du tout si char couple est comprit comme char couple[nb de pseudo-string][longueur de pseudo-string + caractère de fin]; soit char couple [40][2+1];
    But si on se demande ce que retourne couple[40] et ce jusqu'à 46 histoire de se faire plaisir en ajoutant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    printf("couple[39] = %s\n", couple[39]);
    printf("couple[40] = %s\n", couple[40]);
    printf("couple[41] = %s\n", couple[41]);
    printf("couple[42] = %s\n", couple[42]);
    printf("couple[43] = %s\n", couple[43]);
    printf("couple[44] = %s\n", couple[44]);
    printf("couple[45] = %s\n", couple[45]);
    printf("couple[46] = %s\n", couple[46]);
    On obtient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    couple[39] = Jd
    couple[40] = abcd
    couple[41] = d
    couple[42] = BCDEFGHIJ
    couple[43] = EFGHIJ
    couple[44] = HIJ
    couple[45] = 
    couple[46] = �T��
    à 40 on affiche les éléments de basDeCase, à 41 idem - (2+1)?, à 42 les éléments de capitale à 10-1?, à 43 idem - (2+1)?, à 44 idem - (2+1)?, plus rien à 45 et rencontre du 3e type à 46... Est-ce bien raisonnable ?

    Ceci et cela constatés je me disais donc que pour pouvoir gérer un tableau dont on ne connaît pas la taille à l'avance, on pourrait définir au préalable une taille conséquente et constante, récupérer les éléments dans un autre tableau tabDepard en les dénombrant. Si d'aventure, on se retrouve confronté à une fonction toto(tab) et sa petite adresse, il suffira de multiplier le nb de tabDepard par le type traité, non ?... J'oublie un truc ?

  14. #14
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    J'ai fait quelques tests sur mon tableau à 2 dimensions le but étant de trouver un moyen de connaître avant manipulation(s) éventuelle(s) sa taille en mémoire et en éléments :
    C'est bien de chercher par soi-même... C'est la meilleure façon de comprendre ce qui se passe. Toutefois on peut s'interroger sur ta logique où tu combines chacun des 10 caractères "ABCDEFGHIJ" avec chacun des 4 caractères "abcd" (4*10=40) dans un tableau de 39...
    La physique, dont les lois s'appliquent aussi à l'informatique, dit clairement que le contenant ne peut pas être plus petit que le contenu...

    Citation Envoyé par MissLoop Voir le message
    So, strlen() répond bien en nombre d'éléments pseudo-string et char par contre en mémoire il manque 3 octets...
    Je ne comprends pas trop ce que tu entends par "en mémoire il manque"...
    Déjà clarifions certains détails: strlen() a pour but de compter les caractères d'une string. Pour se faire elle utilise un algo super simple: elle compte jusqu'à trouver le '\0'. Donc si tu as un char tab[100]="Hello", strlen(tab) répondra "5". Et comme les éléments se suivent, tu peux même demander strlen(tab+1). Pour la fonction c'est exactement pareil, elle partira du point de départ donné (position 'e') et comptera à partir de là => résultat 4.
    Corollaire: tu veux "vider" ta string, te suffit d'écrire tab[0]='\0' et c'est tout. Même pas besoin de t'occuper du reste. Puisque toutes les fonctions de recherche de string baseront leur traitement sur le '\0', dès qu'il sera rencontré elles s'arrêteront ce qui revient à dire que puisque ces fonctions ne voient aucun caractère avant le '\0', la chaine est informatiquement vide.
    Mais ce n'est pas pour ça qu'il "manque" quoi que ce soit. Le tableau fait tout de même réellement 100 caractères. Ca signifie qu'à un endroit particulier de l'immense suite de cases de ta RAM, il y a 100 caractères dédiés au tableau "tab" et aucune autre variable ne pourra s'y mettre. C"est peut-être là qu'on peut introduire la distinction entre "taille de tab" et "longueur de la chaine tab".

    Accessoirement on notera aussi que le tableau "tab" étant noyé dans la mémoire, il y a donc des caractères avant tab[0] et d'autres après tab[99].

    Citation Envoyé par MissLoop Voir le message
    But si on se demande ce que retourne couple[40] et ce jusqu'à 46 histoire de se faire plaisir
    C'est bien de se faire plaisir. C'est ausi comme ça qu'on apprend.
    Donc on en revient à cette histoire de RAM. En faisant ainsi, tu va taper dans les caractères situés après la zone dédiée à la variable "couple". Tu aurais pu aussi aller voir avant en demandant couple[-1] et autres.
    Toutefois là on doit aborder une autre notion; le UB (Undefined Behavior=Comportement Indéterminé). C'est une notion super importante du C, peut-être la plus importante de toutes.
    Le principe est en soi super simple: le C, pour aller le plus vite possible, ne vérifie jamais la cohérence logique de tes instructions, partant du principe que "le programmeur sait ce qu'il fait". Donc tu peux écrire tout ce que tu veux, si c'est syntaxiquement correct ce sera compilé. Mais si ce que tu écris n'est pas cohérent avec la logique, alors le résultat produit un comportement indéterminé. Donc en résumé même si tu as un tab[10], rien ne t'interdit d'aller dans tab[20]. Mais comme ce n'est pas conceptuellement correct donc comportement indéterminé.
    Et c'est un terme qu'il faut vraiment prendre au premier degré. On ne peut absolument pas prévoir ce qui va se passer. Ca peut marcher, ça peut planter, ça peut marcher les jours pairs et planter les jours impairs, et dans l'absolu ça peut même éteindre ton ordi ou reformater ton disque dur. Comportement i-n-d-é-t-e-r-m-i-n-é
    A partir de là on ne peut plus débattre de ce qui se passe et de si c'est logique ou pas.
    On en revient donc aux fondamentaux: tu as un tableau, tu dois gérer toi-même ce tableau car le C ne le gèrera pas pour toi. Tu as un tableau "couple" taillé à 39, tu as droit à couple[0] jusqu'à couple[38]. Toute autre valeur c'est UB. Mais ça peut fonctionner quand-même et c'est pour ça que dans le cas présent, avec couple taillé à 39 tu peux quand-même y stocker 40 strings et les relire. Il est probable que puisque ton code n'a pas d'autres tableaux, la RAM correspondant au 40° couple reste inoccupée donc utilisable.

    Citation Envoyé par MissLoop Voir le message
    à 40 on affiche les éléments de basDeCase, à 41 idem - (2+1)?, à 42 les éléments de capitale à 10-1?, à 43 idem - (2+1)?, à 44 idem - (2+1)?, plus rien à 45 et rencontre du 3e type à 46... Est-ce bien raisonnable ?
    Comme je te l'ai dit, tu es en UB donc on ne peut pas en débattre. Je peux juste te dire ce que le C tente de faire: Le format "%s" c'est demander à afficher une string, donc partir du début du tableau de char et afficher tous les caractères à suivre jusqu'à trouver un '\0'. Mis à part que tu affiches des zones de la RAM qui ne sont pas à toi (enfin pas à ton tableau) et que de fait c'est UB, il se trouve que dans ce cas ça marche quand-même (parce que tu es encore dans la zone de RAM qui appartient à ton programme) et que dans toute la plage des 256 valeurs possibles pour un char, certains valent parfois 0x00 (noté aussi '\0')

    Citation Envoyé par MissLoop Voir le message
    Ceci et cela constatés je me disais donc que pour pouvoir gérer un tableau dont on ne connaît pas la taille à l'avance, on pourrait définir au préalable une taille conséquente et constante, récupérer les éléments dans un autre tableau tabDepard en les dénombrant. Si d'aventure, on se retrouve confronté à une fonction toto(tab) et sa petite adresse, il suffira de multiplier le nb de tabDepard par le type traité, non ?... J'oublie un truc ?
    Tu en oublies pas mal (c'est normal, il te manque encore des connaissances). Déjà si tu as un "tabDepart" à ta disposition alors tu as sa taille et de là tu peux créer le tableau d'arrivée. Mais il peut arriver effectivement des cas où tu devras gérer des datas dont tu ne connais pas le nombre (lire un fichier, lire une info en provenance du réseau, etc).
    Dans ce cas effectivement tu peux partir de l'hypothèse que les infos ne dépasseront pas une certaine taille X et donc écrire char tab[X]. Mais fais attention que les variables et tableaux de ce type sont stockés dans une zone de la RAM appelée "pile" et que la pile a une taille limitée (de l'ordre du Mo). Ecrire par exemple char tab[50000000] compilera mais risque de en pas être exécuté (plantage au lancement). Donc cette façon de faire n'est valable que pour des "petites" infos.
    Sinon la façon de faire la plus efficace est l'allocation dynamique. Tu as le droit, durant l'exécution, de demander au système de te donner en direct X octets à ta convenance. Là, la mémoire est prise dans une autre zone appelée "le tas" et cette zone est beaucoup plus conséquente. Cela se fait par la fonction malloc(). Et la fonction realloc() permet, elle, d'agrandir une zone déjà allouée.
    Donc l'algo reste simple: on lit X, si pas assez de RAM on alloue ou on agrandit puis ensuite on stocke X et on recommence.

    Citation Envoyé par MissLoop Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for(i=0; i<=39; i++){
    	if(i == 39){
    		printf("%s", couple[i]);
    	}
    	else{
    		printf("%s ", couple[i]);
    	}
    }
    Donc couple[39] c'est UB. Mis à part ce détail, pourquoi faire simple...

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (i=0; i < 39; i++) {
    	printf("%s", couple[i]);
    	if (i != 38) printf(" ");
    }

    Après, utiliser une aussi lourde fonction que printf() pour afficher une simple string ou un simple char...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (i=0; i < 39; i++) {
    	fputs(couple[i], stdout);
    	if (i != (39 - 1)) fputc(' ', stdout);
    }

    Et (personnellement) je préfère baser mes algos (quand c'est symétrique) non pas sur la fin de la boucle (déjà parce que tableau de 39 mais obligé de tester 39-1 et surtout fin toujours sujette à évolution future) mais sur le début (qui, lui, reste immuable)
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (i=0; i < 39; i++) {
    	if (i > 0) fputc(' ', stdout);
    	fputs(couple[i], stdout);
    }

    Et tu remarqueras que l'aération des instructions rend la lecture plus aisée sans ôter quoi que ce soit à l'efficacité du code

  15. #15
    Invité
    Invité(e)
    Par défaut
    La physique, dont les lois s'appliquent aussi à l'informatique, dit clairement que le contenant ne peut pas être plus petit que le contenu...
    Tu réponds à une question que je me posais tab[nb d'index de 0 à n][] ou tab[nb effectif d'éléments][]?... Et ça explique la suite :

    Je ne comprends pas trop ce que tu entends par "en mémoire il manque"...
    Je me suis emmêlée les neurones, enfin les synapses : celles qui transmettaient l'observation de strlen() et de sizeof(), j'ai concaténé les deux. J'aurais dû écrire : So, strlen() répond bien en nombre d'éléments pseudo-string et char par contre en mémoire il manque 3 octets avec sizeof(). Explication de mon désert de Gobi cérébral : j'ai en tout 10*3*4 caractères : 10 de capitale par 3 d'un char de basDeCase par 4 de la contenance de couple soit 120 et non 117 ; soit 3 octets de moins, un char valant,... ou occupant plutôt 1o. On retrouve dans l'initialisation de couple les mêmes nombres en 39*(2+1) et 40*(2+1) qui en dernier lieu est plus en phase avec la réalité. En utilisant sizeof() sur une initialisation char couple[40][2+1]; dans tous les cas on tombe bien sur 40 pseudo-string de 2 caractères et de 120 caractères en tout les '\0' compris donc.

    Et c'est un terme qu'il faut vraiment prendre au premier degré. On ne peut absolument pas prévoir ce qui va se passer. Ca peut marcher, ça peut planter, ça peut marcher les jours pairs et planter les jours impairs, et dans l'absolu ça peut même éteindre ton ordi ou reformater ton disque dur. Comportement i-n-d-é-t-e-r-m-i-n-é
    Ce n'est pas très rassurant ! Avec ma curiosité et mes expérimentations, partant du principe que la plupart du temps, je ne sais pas vraiment ce que je fait, l'idée de revenir d'un voyage de l'UB sans DD me ravit moyennement.

    On en revient donc aux fondamentaux: tu as un tableau, tu dois gérer toi-même ce tableau car le C ne le gèrera pas pour toi.
    Ok donc dans les fondamentaux : 1. On ne touche pas à la donnée de départ, 2. On gère soi-même un tableau en C. Tu n'aurais pas par hasard un fondamental pour éviter le monde merveilleux de l'UB dans tous les cas ?

    Donc couple[39] c'est UB.
    J'ai défini dans le tableau 40-1 éléments et je l'ai rempli avec 40 et il affiche bien le dernier composé de J et de d et sizeof() affiche en tout 117 caractères au lieu de 120 soit moins J + d + '\0'. Jd est un "rescapé" de l'UB ?

    Après, utiliser une aussi lourde fonction que printf() pour afficher une simple string ou un simple char...
    Généralement, on utilise printf() dans quelles circonstances ?

    Et (personnellement) je préfère baser mes algos (quand c'est symétrique)...
    Tu parles de la symétrie rédactionnelle ou je suis encore dans l'UB ?

    En tous cas super tes simplifications de code (et tes explications/suggestions), ça en jette ; l'efficacité de Tyler Durden et la simplicité du Dude, Ze Big Lebowski ! J'vais r'prendre un white russian.

  16. #16
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Tu réponds à une question que je me posais tab[nb d'index de 0 à n][] ou tab[nb effectif d'éléments][]?...
    Si ce n'est pas ton cours de C alors la logique devrait te donner la réponse. Tu as besoin de "nb" tu définis un tab[nb]. Ca c'est l'évidence.
    Et puisque le premier commence à [0], le dernier finit à [nb-1].

    Citation Envoyé par MissLoop Voir le message
    En utilisant sizeof() sur une initialisation char couple[40][2+1]; dans tous les cas on tombe bien sur 40 pseudo-string de 2 caractères et de 120 caractères en tout les '\0' compris donc.
    Oui. Comme pour mon char tab[100]="Hello". strlen(tab) donnera 5 mais sizeof(tab) donnera 100. Mais si tu rajoutes char* pt=tab, entrant ainsi dans le monde merveilleux des pointeurs, même s'ils sont utilisables comme des tableaux (ex printf("%c %c\n", tab[0], pt[1]) donnera "He") ils n'en sont pas réellement et là sizeof(pt) te donnera 8.

    Citation Envoyé par MissLoop Voir le message
    Ce n'est pas très rassurant ! Avec ma curiosité et mes expérimentations, partant du principe que la plupart du temps, je ne sais pas vraiment ce que je fait, l'idée de revenir d'un voyage de l'UB sans DD me ravit moyennement.
    J'ai exagéré car ton OS se protège lui-même de tes propres actions inconsidérées. Mais c'est bien d'être conscient du danger de l'UB. Quand j'étais en école, un de mes profs nous a dit (info/intox j'en sais rien) qu'une des premières fusées Ariane s'était crashée parce que les codeurs avaient travaillé en non-signé. Or si dans l'hémisphère Nord le sinus de l'angle est compris entre 0 et pi/4, le cosinus lui est compris entre pi/2 et -pi/2

    Citation Envoyé par MissLoop Voir le message
    Ok donc dans les fondamentaux : 1. On ne touche pas à la donnée de départ, 2. On gère soi-même un tableau en C.
    Me souviens pas avoir dit "on ne touche pas à la donnée de départ" ? Et quand je dit "on gère soi-même" c'est juste "on veille en permanence à ne jamais dépasser les limites".

    Citation Envoyé par MissLoop Voir le message
    Tu n'aurais pas par hasard un fondamental pour éviter le monde merveilleux de l'UB dans tous les cas ?
    Ne pas faire de C. En as-tu réellement besoin? Tu veux piloter des cartes électroniques? Créer des drivers? Concevoir un OS? Parce que c'est un peu les seules choses possibles en C. Enfin on peut aussi créer des logiciels comme paint ou excel mais là il va te falloir la nuit des temps. Tu n'as pas pensé à Python par exemple? Là tu pourras rapidement programmer des trucs sympas avec une petite IHM...

    Citation Envoyé par MissLoop Voir le message
    J'ai défini dans le tableau 40-1 éléments et je l'ai rempli avec 40 et il affiche bien le dernier composé de J et de d et sizeof() affiche en tout 117 caractères au lieu de 120 soit moins J + d + '\0'. Jd est un "rescapé" de l'UB ?
    Exactement. Ton tableau reste dans ta RAM, il n'y a pas d'autres variables qui viennent se mettre "pile poil" en case[39] donc ça reste ok.

    Citation Envoyé par MissLoop Voir le message
    Généralement, on utilise printf() dans quelles circonstances ?
    printf signifie "print format". Donc dès que tu dois afficher des données avec un format précis. Du nombre (ou un calcul), des chaines ("des", pas "une") ou bien une info avec un enrobage textuel (ex printf("Votre chaine est %s, sa longueur est %lu\n", tab, strlen(tab)).

    Citation Envoyé par MissLoop Voir le message
    Tu parles de la symétrie rédactionnelle ou je suis encore dans l'UB ?
    Non ce n'était plus de l'UB, juste de la symétrie de logique. Afficher "trucA<espace>trucB" c'est afficher l'espace après trucA ou l'espace avant trucB. Moi j'ai choisi "avant trucB" ce qui me permet de tester sur l'indice supérieur à 0 et je ne m'embête pas avec des "oh là là est-ce i==40? i==39?? i==38???" devenus métaphysiquement inutiles.

  17. #17
    Invité
    Invité(e)
    Par défaut
    Me souviens pas avoir dit "on ne touche pas à la donnée de départ" ?
    Si, si c'est pas du jour certes,... et tu parlais de la donnée d'origine :
    Ensuite il est possible que Python offre des syntaxes permettant à la fois la copie et le travail (comme le ' '.join(str(x) for x in data)) si c'est le cas c'est bonus sinon tant pis, tu te coltines la copie à la mano avec ton for i in range(len(list4)): sys.stdout.write(str(list4[i]) +'\n') mais ça ne remet pas en cause le pricipe de base: on ne touche pas à la donnée d'origine.
    https://www.developpez.net/forums/d2.../#post11542566

  18. #18
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par MissLoop Voir le message
    Si, si c'est pas du jour certes,... et tu parlais de la donnée d'origine :

    https://www.developpez.net/forums/d2.../#post11542566
    Oui c'est vieux et c'est sorti du contexte. Dans ce fil, tu voulais convertir une data_origine en data_a_afficher puis l'afficher, puis ensuite reconvertir la data_a_afficher en data_origine.
    Effectivement là ce n'est pas un truc à faire, dans aucun langage. Parce que tous les langages possèdent des outils qui permettent de convertir une data_origine en data_a_afficher_au_moment_de_l_affichage.
    Exemple: int i=123; printf("i=%d\n", i) => le nombre 123 est converti en string par printf(). C'est aussi le cas dans le fil de 2020 où je t'indique l'instruction sys.stdout.write("".join("%s\n" % l for l in list4)) permettant d'afficher ta liste en te disant qu'il y a eu création "à la volée" de la data_a_afficher à partir de la data_origine.

    Mais si tu dois transformer ta donnée pour la faire évoluer, alors oui tu as bien évidemment le droit d'y toucher...

  19. #19
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 672
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 672
    Points : 43 724
    Points
    43 724
    Par défaut
    Quand j'étais en école, un de mes profs nous a dit (info/intox j'en sais rien) qu'une des premières fusées Ariane s'était crashée parce que les codeurs avaient travaillé en non-signé.
    Le crash de la 1ère Ariane 5 est dû à un dépassement de capacité. Bel exemple de comportement indéterminé. La fusée n'a pas été détruite à cause de cela mais a subi un violent changement de trajectoire. Ceci ayant endommagé les boosters, et la trajectoire devenant incontrôlable, la fusée fut détruite.

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

Discussions similaires

  1. Question sur les boucles for, while
    Par Spotjaune dans le forum Débuter
    Réponses: 9
    Dernier message: 18/10/2015, 11h28
  2. while et for sur tableau
    Par macbida dans le forum Langage
    Réponses: 1
    Dernier message: 11/01/2012, 14h21
  3. Réponses: 11
    Dernier message: 28/04/2008, 16h29
  4. [MySQL] Résultat de requête différent sur 2 serveurs identiques
    Par schlitters dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 17/12/2005, 00h24
  5. Sum différents sur sur une même table ...
    Par Saloucious dans le forum Langage SQL
    Réponses: 4
    Dernier message: 05/10/2005, 15h51

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