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 :

Amélioration d'un programme, le pendu, passage du statique au dynamique.


Sujet :

C

  1. #1
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Avril 2020
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2020
    Messages : 88
    Points : 48
    Points
    48
    Par défaut Amélioration d'un programme, le pendu, passage du statique au dynamique.
    Bonjour,

    Voici mon programme ci dessous :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
     
    #define taille_mot_secret 7
     
    int main(void)
    {
    	char mot_secret[] = "Bonjour";
    	char mot_rentrer_par_utilisateur[taille_mot_secret+1]; //+1 => reservation '\0' (carac fin chaine)
    	int nombre_vie = 10;
    	char lettre_utilisateur;
     
    	// Initialisation du mot rentrer par l'utilisateur
    	// ==================================================================================
    	for (int i = 0; i < taille_mot_secret; i++)
    		mot_rentrer_par_utilisateur[i] = '_';
    	mot_rentrer_par_utilisateur[taille_mot_secret] = '\0';
    	// ==================================================================================
     
    	do
    	{
    		// Récupération saisie utilisateur
    		// ==========================================================================
    		printf("Entrer une lettre majuscule ou minuscule ?\n");
    		scanf("%c", &lettre_utilisateur);
    		scanf("%*c");
    		// ==========================================================================
     
    		// Vérification de la saisie utilisateur
    		// ==========================================================================
    		bool presence_lettre = false;
    		for (int i = 0; i < taille_mot_secret; i++)
    		{
    			if (mot_secret[i] == lettre_utilisateur)
    			{
    				presence_lettre = true;
    				mot_rentrer_par_utilisateur[i] = lettre_utilisateur;
    			}
    		}
    		// ==========================================================================
     
    		// Affichage en fonction de la présence de la lettre
    		// ==========================================================================
    		if (presence_lettre)
    			printf("Votre lettre : %c est bien présente dans le mot : \"%s\"\n", lettre_utilisateur, mot_rentrer_par_utilisateur);
    		else
    		{
    			nombre_vie--;
    			printf("Votre lettre n'est pas présente, il vous reste %d vie\n", nombre_vie);
    		}
    		// ==========================================================================
     
    		// Test de la victoire
    		// ==========================================================================
    		if (strcmp(mot_secret, mot_rentrer_par_utilisateur) == 0)
    		{
    			printf("vous avez trouvé le mot : \"%s\"", mot_secret);
    			break;
    		}
    		// ==========================================================================
     
    	} while (nombre_vie > 0);
     
    	// Affichage lorsque plus de vie
    	// ==========================================================================
    	if (nombre_vie == 0)
    		printf("Vous n'avez pas trouvez le mot : \"%s\"", mot_secret);
    	// ==========================================================================
     
    	return 0;
    }
    Ce qui me dérange est la chose suivante :
    Je suis obligé de passé par une directive de préprocesseur, c'est à dire, un #define taille_mot_secret 7 pour définir la taille du mot secret dans le tableau.
    J'ai essayé de la faire dynamiquement, c'est à dire, de faire la chose suivante :
    - supprimer le #define taille_mot_secret 7
    - taille_mot_secret = strlen(mot_secret)
    - mot_rentrer_par_utilisateur[taille_mot_secret + 1]

    Ceci ne fonctionne pas car si j'ai bien compris car la taille d'un tableau ne peut être allouer que avant la compilation. Vous confirmez ?

    Je pense qu'il faut passer par l'allocation dynamique de mémoire, mais je n'en suis pas encore la, dans mon apprentissage du langage C.
    Sinon, connaissez vous une solution plus simple ?

    Merci pour votre aide.

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par zephyre Voir le message
    Je suis obligé de passé par une directive de préprocesseur, c'est à dire, un #define taille_mot_secret 7 pour définir la taille du mot secret dans le tableau.
    C'est effectivement le but du préprocesseur: définir des pseudo-constantes et pseudo-fonctions. Les constantes servent à éviter de répéter leur valeur dans tout le code (en cas de modif on ne modifie qu'une fois et on recompile) et les pseudo-fonctions c'est pour aller plus vite (un appel de fonction étant toujours (relativement) long).
    C'est sympa tant qu'on n'en abuse pas (comme tout d'ailleurs). Surtout ne pas oublier que la macro est réécrite de façon intégrale. Définir par exemple un #define CARRE(n) ((n) * (n)) écrira littéralement l'opération partout où on appelera la pseudo-fonction. Ecrire par exemple int v=5; printf("valeur=%d\n", CARRE(v)) sera remplacé par int v=5; printf("valeur=%d\n", ((v) * (v))). Les parenthèses servent donc à ne pas exploser connement en vol concernant les opérations et leurs priorités (CARRE(x+y)!!!). Et c'est donc aussi pour bien identifier les macros dans un code, et en particulier aussi pour éviter les effets de bord (CARRE(v++)!!!!!!!!!) contre lesquels on n'a aucune solution (hormis le fait de ne pas écrire de pré/post incrémentation dans les paramètres qu'on envoie aux macros), qu'on prend l'habitude de les écrire en majuscules.

    Citation Envoyé par zephyre Voir le message
    J'ai essayé de la faire dynamiquement, c'est à dire, de faire la chose suivante :
    - supprimer le #define taille_mot_secret 7
    - taille_mot_secret = strlen(mot_secret)
    - mot_rentrer_par_utilisateur[taille_mot_secret + 1]

    Ceci ne fonctionne pas car si j'ai bien compris car la taille d'un tableau ne peut être allouer que avant la compilation. Vous confirmez ?
    Je confirme. Un tableau doit avoir une taille figée définie par le programmeur. Petite parenthèse toutefois, on a le droit d'écrire char tab[]={'H', 'e', 'l', 'l', 'o'} sans préciser de taille. Le compilateur compte alors combien d'éléments (5) et remplace implicitement char tab[] par char tab[5]. C'est la seule exception. On a bien entendu le droit de mettre "5" si on veut ou même toute autre valeur si on le désire, mais bien évidemment on évite de mettre une valeur inférieure car le compilo ne corrigera pas (peut-être éventuellement préviendra-t-il mais autant éviter les problèmes idiots).

    Citation Envoyé par zephyre Voir le message
    Je pense qu'il faut passer par l'allocation dynamique de mémoire, mais je n'en suis pas encore la, dans mon apprentissage du langage C.
    Ok, petit coup de pouce car tu as l'air motivé (en tout cas tu cherches et c'est ça l'important): tu remplaces mot_rentrer_par_utilisateur[taille_mot_secret + 1] par char* mot_rentrer_par_utilisateur=malloc((taille_mot_secret + 1) * sizeof(*mot_rentrer_par_utilisateur)). Et quand tu n'as plus besoin de ton tableau (donc en fin de programme) tu rajoutes free(mot_rentrer_par_utilisateur).
    Attention, c'est un ersatz rapide de ce qu'il faut faire (la procédure normale veut qu'on vérifie la réussite de l'allocation avant de continuer en codant une alternative si l'allocation échoue) donc c'est juste pour que tu aies le plaisir de voir ton code fonctionner mais ne prend pas l'habitude de faire du malloc() sans avoir d'abord appris à le faire correctement.

    Citation Envoyé par zephyre Voir le message
    Sinon, connaissez vous une solution plus simple ?
    Il y a les VLA (Variable Length Array). C'est à mi-chemin entre le tableau fixe et le malloc. Grosso-modo tu définis ton tableau ainsi: char mot_rentrer_par_utilisateur[taille_mot_secret + 1] et ça le fait. Ou bien ça ne le fait pas et ton programme crashe lamentablement. Et en plus tu n'as absolument aucun aucun moyen de checker la réussite ou l'échec de la manip (contrairement à malloc() qu'on peut vérifier avant de continuer). Donc je t'en parle parce que ça fait partie du langage donc de ta future culture C mais c'est une pratique très décriée, absolument pas fiable donc à ne pas utiliser sur des programmes sensibles. Il me semble même que sa suppression a été envisagée.
    Mais pour de petits codes rapides et/ou de tests si tu veux les utiliser...

    Et sinon une autre pratique intermédiaire entre le malloc (efficace mais douloureux à mettre en oeuvre) et le VLA (pratique mais sans garantie) c'est de définir non pas la taille mais la taille maximale du mot secret, style #define SZ_SECRET_MAX (20).
    Ensuite tu définis ton tableau char mot_rentrer_par_utilisateur[SZ_SECRET_MAX + 1] et lors de la saisie tu t'assures que ce que rentre l'utilisateur ne dépasse pas cette taille (ou alors il doit re-saisir). Et ensuite, dans le code, tu travailles avec la taille réellement saisie et donnée par strlen().

    Citation Envoyé par zephyre Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (int i = 0; i < taille_mot_secret; i++)
    	mot_rentrer_par_utilisateur[i] = '_';
    memset(mot_rentrer_par_utilisateur, '_', taille_mot_secret).
    Et peut-être ensuite tu te dis que tu gagnerais à ne pas avoir de variable aux noms interminables (en tout cas moi j'y aurais gagné )
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre du Club
    Homme Profil pro
    Ingénieur
    Inscrit en
    Avril 2020
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2020
    Messages : 88
    Points : 48
    Points
    48
    Par défaut
    Merci pour toutes ces précisions Sve@r.
    Je clos le sujets.

  4. #4
    Membre averti
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Points : 411
    Points
    411
    Par défaut
    Citation Envoyé par zephyre Voir le message
    (...)
    J'ai essayé de la faire dynamiquement, c'est à dire, de faire la chose suivante :
    - supprimer le #define taille_mot_secret 7
    - taille_mot_secret = strlen(mot_secret)
    - mot_rentrer_par_utilisateur[taille_mot_secret + 1]

    Ceci ne fonctionne pas car si j'ai bien compris car la taille d'un tableau ne peut être allouer que avant la compilation. Vous confirmez ?
    (...)
    Ceci crée un VLA (Variable Length Array) dont parle Sve@r, et cela devrait compiler sur tout compilateur conforme à la norme standard du C dans sa révision C99 (le C, comme tu le sais sans doutes, est un langage standardisé pour la première fois en 1989/90 (C89 ou C90), le standard suivant étant la révision C99 datant de 1999 où les VLA sont introduits - le dernier standard adopté à ce jour est le C17 de 2017).

    Si ton code ne compile pas, c'est sans doutes que tu utilises Visual Studio et le compilateur de Microsoft, qui n'a pas jugé utile de rendre son compilateur conforme au standard C99.

    Cela compile très bien avec gcc et Clang, et même TCC (Tiny C Compiler) et une floppée d'autres compilateurs.

    Essaye avec Codeblocks et le compilateur gcc (MinGW sous Windows)...

    Cette utilisation des VLA peut-être dangereuse (comme beaucoup de choses en C), si tu n'as pas vérifié au préalable que la longueur de la chaîne était limitée à quelque chose d'acceptable, et tenant dans la mémoire de la pile réservée au fonctionnement de ton programme.

    Tout comme c'est dangereux d'allouer un gros tableau statique.

    Comme il n'y a pas de moyen portable de déterminer la taille disponible de mémoire sur la pile, c'est hasardeux d'allouer de grosses quantités, car tu risques d'exploser sa capacité (stack overflow).

    Citation Envoyé par Sve@r Voir le message
    (...)
    Il y a les VLA (Variable Length Array). C'est à mi-chemin entre le tableau fixe et le malloc. Grosso-modo tu définis ton tableau ainsi: char mot_rentrer_par_utilisateur[taille_mot_secret + 1] et ça le fait. Ou bien ça ne le fait pas et ton programme crashe lamentablement. Et en plus tu n'as absolument aucun aucun moyen de checker la réussite ou l'échec de la manip (contrairement à malloc() qu'on peut vérifier avant de continuer). Donc je t'en parle parce que ça fait partie du langage donc de ta future culture C mais c'est une pratique très décriée, absolument pas fiable donc à ne pas utiliser sur des programmes sensibles. Il me semble même que sa suppression a été envisagée.
    Mais pour de petits codes rapides et/ou de tests si tu veux les utiliser...
    (...)
    +1 pour ta réponse à la fois complète et didactique.

    Sur les VLA, juste quelques précisions. A ma connaissance il n'a jamais été envisagé de les supprimer du standard du C (et je pense qu'il faut être moins dramatique sur le sujet des VLA).

    En revanche, en 1999, les petits éditeurs de compilateurs pour l'embarqué râlaient parce que le Comité de standardisation avait introduit de nombreux changements et trop rapidement à leur goût, dont ils n'avaient pas besoin dans les environnements très contraints auxquels il avaient affaire et avaient massivement décidé de rester en C89. Du coup, lors de la révision C11, le Comité a décidé de rendre certaines exigences du C99 optionnelles (le support des nombres complexes et les VLA) et certaines nouveautés du C11 aussi (<threads.h>, <stdatomic.h>, etc.) pour rendre plus facile l'adoption du nouveau standard par plus de monde.

    Les pointeurs sur VLA sont une façon élégante, pratique et moderne de programmer en C, qui ne souffre pas des risques d'utilisation incontrôlés sur la pile, puisque l'allocation est faite avec malloc(), qui permettent par exemple de gérer élégamment des tableaux multidimensionnels sur de la mémoire contiguë, et de passer des tableaux à des fonctions avec leur taille dont les prototypes sont compatibles que le tableau soit alloué de façon statique ou de façon dynamique, y compris pour les tableaux multidimentionels, de copier un tableau dynamique mutidimensionnel avec memcpy(), etc.

    Plus d'infos ici :

    https://gustedt.wordpress.com/2011/0...odified-types/
    https://gustedt.wordpress.com/2011/0...ion-arguments/

    Tout ceci passe visiblement par dessus la tête de Microsoft, qui n'est pas un petit éditeur de compilateur, mais qui choisit de ne pas implémenter les VLA en les diabolisant.

  5. #5
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par -Eks- Voir le message
    Tout ceci passe visiblement par dessus la tête de Microsoft, qui n'est pas un petit éditeur de compilateur, mais qui choisit de ne pas implémenter les VLA en les diabolisant.
    sur ce coup , je trouve qu'ils n'ont pas tord, je déconseille les VLA , et en général , je conseille plus d'utiliser malloc.

  6. #6
    Membre averti
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Points : 411
    Points
    411
    Par défaut
    Citation Envoyé par Kannagi Voir le message
    sur ce coup , je trouve qu'ils n'ont pas tord, je déconseille les VLA , et en général , je conseille plus d'utiliser malloc.
    Ils ont tort de les diaboliser, parce que c'est une vue très courte de ce que peuvent faire les VLA, comme je l'ai indiqué, tu peux utiliser des pointeurs sur VLA avec malloc() et avoir le meilleur des deux mondes.

    cf :

    Citation Envoyé par -Eks- Voir le message
    (...)
    Les pointeurs sur VLA sont une façon élégante, pratique et moderne de programmer en C, qui ne souffre pas des risques d'utilisation incontrôlés sur la pile, puisque l'allocation est faite avec malloc(), qui permettent par exemple de gérer élégamment des tableaux multidimensionnels sur de la mémoire contiguë, et de passer des tableaux à des fonctions avec leur taille dont les prototypes sont compatibles que le tableau soit alloué de façon statique ou de façon dynamique, y compris pour les tableaux multidimentionels, de copier un tableau dynamique mutidimensionnel avec memcpy(), etc.
    (...)
    Lis les articles de Jens Gustedt (c'est l'auteur de "Modern C") dont j'ai donné les liens.

    Sinon, voilà un petit exemple de mon cru de ce dont je parle, permis par la notation de type VLA et illustrant les différents bénéfices que j'évoque :

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    void print_array(size_t lignes, size_t colonnes, int array[][colonnes]) {
            for (size_t i = 0; i < lignes; i++) {
                    for (size_t j = 0; j < colonnes; j++)
                            printf("%d\t", array[i][j]);
                    printf("\n");
            }
    }
     
    int main(void)
    {
            size_t colonnes = 5;
            size_t lignes = 2;
            int truc = 0;
     
            int (*tableau2D_dyn)[colonnes] = malloc(lignes * sizeof(*tableau2D_dyn));
            for (size_t i = 0; i < lignes; i++)
                    for (size_t j = 0; j < colonnes; j++)
                            tableau2D_dyn[i][j] = truc++;
     
            printf("Contenu de tableau2D_dyn :\n");
            print_array(lignes, colonnes, tableau2D_dyn);
     
            int tableau_statique[2][5];
            memcpy(tableau_statique, tableau2D_dyn, lignes * colonnes * sizeof(int));
     
            free(tableau2D_dyn);
     
            printf("Contenu de tableau_statique :\n");
            print_array(lignes, colonnes, tableau_statique);
     
            return 0;
    }
    Avec un tableau 2D classiquement alloué avec malloc() en C89, tu dois allouer avec malloc() de la mémoire pour des pointeurs pour autant de lignes que tu veux avoir, et ensuite, pour chaque pointeur, allouer avec malloc() de nouveau une quantité de mémoire correspondant aux données sur tes colonnes. Tu peux alors utiliser la notation array[1][2] pour accéder à tes données, mais tu as une mémoire allouée de façon fragmentée et non contiguë et des appels multiples à malloc() et à free().

    Utiliser les pointeurs sur VLA permet de te libérer de cela.

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par -Eks- Voir le message
    Si ton code ne compile pas, c'est sans doutes que tu utilises Visual Studio et le compilateur de Microsoft, qui n'a pas jugé utile de rendre son compilateur conforme au standard C99.
    Voilà, petite gifle gratuite au passage...

    Citation Envoyé par -Eks- Voir le message
    +1 pour ta réponse à la fois complète et didactique.
    Merci . En revanche j'ai eu un "-1" sans savoir ce que j'ai dit qui ne va pas. Bof, probablement un de ces aigris du forum que j'ai taclés en leur temps pour leurs absurdités et qui reviennent de temps en temps montrer par leur mesquinerie qu'ils ont systématiquement lamentablement échoué dans leur argumentation...

    Citation Envoyé par -Eks- Voir le message
    et je pense qu'il faut être moins dramatique sur le sujet des VLA.
    C'est toujours une histoire de rapport coût/risque. Si je dois compter des chaussettes, j'envisagerai sans souci les VLA. Si je dois programmer un pilote automatique de Boing ou une surveillance de centrale nucléaire, j'y réfléchirai plus attentivement...

    Citation Envoyé par -Eks- Voir le message
    Tout ceci passe visiblement par dessus la tête de Microsoft, qui n'est pas un petit éditeur de compilateur, mais qui choisit de ne pas implémenter les VLA en les diabolisant.
    Ah, ça c'est la gifle retour (comme les oreilles on met toujours les gifles par deux )

    Citation Envoyé par -Eks- Voir le message
    Avec un tableau 2D classiquement alloué avec malloc() en C89, tu dois allouer avec malloc() de la mémoire pour des pointeurs pour autant de lignes que tu veux avoir, et ensuite, pour chaque pointeur, allouer avec malloc() de nouveau une quantité de mémoire correspondant aux données sur tes colonnes. Tu peux alors utiliser la notation array[1][2] pour accéder à tes données, mais tu as une mémoire allouée de façon fragmentée et non contiguë et des appels multiples à malloc() et à free().

    Utiliser les pointeurs sur VLA permet de te libérer de cela.
    Moui. Il y a tout de même d'autres solutions. Tu peux par exemple allouer un simple int * avec lig*col. Ensuite tu perds la notation array[x][y] pour une notation array[x*nb_col + y] mais ça se gère.
    Sinon il y a une autre solution (que j'ai apprise ici mais je me souviens plus qui l'a expliquée, je crois que c'est Medinoc): tu alloues un tableau 1D et un tableau de pointeurs où chaque pointeur pointera vers la première case de chaque case censées commencer les "lignes" de la zone
    Code c : 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
    // Allocation d'un tableau 2D
    // L'allocation se fera au travers d'une zone 1D et d'un tableau de pointeurs,
    // Chaque pointeur pointant vers chaque début de "ligne" de la zone
    int** matrice2D(size_t lig, size_t col) {
    	int* zone;			// Zone correspondant au tableau 2D
    	int** final;		// Tableau final
     
    	// Allocation de la zone mémoire représentant tout le tableau
    	zone=malloc(lig*col*sizeof(*zone));
    	if (zone == NULL) return NULL;
     
    	// Allocation des pointeurs référençant les lignes de la zone
    	final=malloc(lig * sizeof(*final));
    	if (final == NULL) {
    		free(zone);
    		return NULL;
    	}
     
    	// Remplissage des pointeurs avec chaque début de ligne de la zone
    	for (size_t i=0; i < lig; i++) final[i]=zone + i * col;
     
    	// Le tableau final est créé
    	return final;
    }

    Le tableau retourné par la fonction reste accessible en notation [x][y]. Et pour libérer suffit de libérer la case[0] (qui est la zone 2D) puis le tableau de pointeurs...

    Sans parler de diabolisation, perso je n'aime pas qu'un truc puisse ne pas se faire sans que j'en sois informé...
    Mon Tutoriel sur la programmation «Python»
    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
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre averti
    Homme Profil pro
    très occupé
    Inscrit en
    Juillet 2014
    Messages
    137
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : très occupé

    Informations forums :
    Inscription : Juillet 2014
    Messages : 137
    Points : 411
    Points
    411
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    (...)
    Moui. Il y a tout de même d'autres solutions. Tu peux par exemple allouer un simple int * avec lig*col. Ensuite tu perds la notation array[x][y] pour une notation array[x*nb_col + y] mais ça se gère.
    Sinon il y a une autre solution (que j'ai apprise ici mais je me souviens plus qui l'a expliquée, je crois que c'est Medinoc): tu alloues un tableau 1D et un tableau de pointeurs où chaque pointeur pointera vers la première case de chaque case censées commencer les "lignes" de la zone
    (...)
    Le tableau retourné par la fonction reste accessible en notation [x][y]. Et pour libérer suffit de libérer la case[0] (qui est la zone 2D) puis le tableau de pointeurs...
    Ces solutions fonctionent, mais sont relativement complexes (calcul des indices fictifs dans un tableau 1D aplatit, ou fonction d'une 30aine de lignes avec deux malloc et calcul des adresses), et elles se complexifient encore avec le nombre de dimensions. Avec les pointeurs de VLA, tu alloues ta zone contiguë en une ligne et un seul malloc() ou calloc().

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
         size_t d1 = 3, d2 = 4, d3 = 10, d4 = 30;
     
         int (*arr)[d2][d3][d4] = calloc(d1, sizeof *arr);
         /* on peut maintenant accéder à arr[2][3][9][29] */
    Citation Envoyé par Sve@r Voir le message
    Sans parler de diabolisation, perso je n'aime pas qu'un truc puisse ne pas se faire sans que j'en sois informé...
    Microsoft en informe les lecteurs de ses communiqués et je parle de diabolisation parce que Microsoft utilise l'argument des dangers de l'utilisation des VLA alloués sur la pile pour justifier leur décision de ne pas les supporter, en comparant les VLA à gets() qui a été supprimée du standard.

    https://devblogs.microsoft.com/cppbl...-length-arrays

    On retrouve ce genre d'affirmations dans plusieurs de leurs communiqués en 2020 lorsqu'ils ont décidé de se mettre à la page de C11 et C17 (en se rendant compte qu'ils avaient laissé leur compilateur C quasi à l'abandon pendant 30 ans, bloqué sur C89/90 avec uniquement des changements communs à C++ et donc, en fait, utiles à leur compilateur C++) et dans des pages plus actuelles sur leur conformité aux standards, mais je n'ai plus les URL sous la main.

    Du coup, de nombreux développeurs retiennent "les VLA c'est mal" et Microsoft nous protège contre elles.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    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 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Franchement je suis d'accord avec Microsoft, il faut moins de tableaux sur la pile, et pas plus.
    En revanche c'est quand même un manque d'une fonctionnalité majeure de la norme.
    Ce que je me demande, c'est son taux d'utilisation, i.e. la proportion des programmes C que ça va bloquer (surtout comparé à d'autres fonctionnalités que moi je considère indispensables, comme le snprintf() qui accepte un buffer nul et retourne la longueur qu'aura la chaîne).

    PS: À ma connaissance, c'est pour Visual 2015 que Microsoft s'est réveillé, et qu'ils ont (enfin!) commencé à implémenter des fonctionnalités du C99. Je suis agréablement surpris qu'ils implémentent C17 en 2020, je n'attendais pas ça avant 2030

    Edit: J'ai lu l'article sur les "types VLA". Ça peut possiblement aider, mais selon l'organisation du compilateur ça peut être quasi-impossible à implémenter sans tout réécrire (parce qu'il n'y a rien d'autre dans tout le langage dont le sizeof ne soit pas fixé à la compilation... même en C++ d'ailleurs).
    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.

  10. #10
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Bonjour,
    je me permets d'intervenir car les VLA … ok ; il y a du pour, du contre, du pour pour être contre, etc … C'est un peu comme alloca.
    Mais surtout ce qui est important est le support de la notation VLA qui a pour grand mérite d'augmenter la lisibilité du code. On peut le constater par exemple entre un classique C89 void matrix_mul(double **dst, double **op1, double **op2, int l, int m, int n) et un plus moderne C11 (et suivant) void matrix_mul(size_t l, size_t m, size_t n, double dst[l][n], double op1[l][m], double op2[m][n]); (et je ne surcharge pas avec des restrict et static). Bon c'est un exemple que l'on ne retrouvera pas (quoique) dans la littérature, mais c'est pour donner l'idée.

    C'est d'ailleurs un des principes (le 15) abordés dans le document Programming Language C - C23 Charter :

    15. Application Programming Interfaces (APIs) should be self-documenting when possible. In particular, the order of parameters in function declarations should be arranged such that the size of an array appears before the array. The purpose is to allow Variable-Length Array (VLA) notation to be used. This not only makes the code's purpose clearer to human readers, but also makes static analysis easier. Any new APIs added to the Standard should take this into consideration.

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

Discussions similaires

  1. Amélioration d'un programme
    Par grayson dans le forum Calcul scientifique
    Réponses: 2
    Dernier message: 05/06/2015, 15h17
  2. Réponses: 41
    Dernier message: 11/07/2012, 08h42
  3. [thread] amélioration d'un programme
    Par ChipsterJulien dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 06/06/2010, 13h21
  4. Réponses: 4
    Dernier message: 02/05/2007, 16h18

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