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 :

[c99] VLA et appel de fonction


Sujet :

C

  1. #1
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut [c99] VLA et appel de fonction
    Bonjour,

    Je m'essaye aux tableaux dynamiques avec le code suivant, mais j'ai visiblement un soucis que je ne trouve pas.

    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
     
    /* Pleins de choses avant */
     
    	    int nodes[get_nb()][get_node_number(0)];
     
    	    memset (nodes, 
    		    0, 
    		    get_nb() * get_node_number(0) * sizeof (int));
     
    /*	    DEBUGSTR1 ("Size : %lu", sizeof (nodes_if_lists)); */
    /*	    nodes_if_lists[1][1] = 12; */
    /*	    DEBUGSTR1 ("content : %d", nodes_if_lists[1][1]); */
     
    	    save_nodes (nodes);
     
    /* Pleins de choses apres */
    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
    /**
     * Save identifiers of all nodes
     * 
     *@param nodes : allocated list in which function will store data.
     *       
     *@return void
     *
     */
    void save_nodes (int ** nodes)
    {
        int i;
        int j;
     
        if (nodes != NULL)
        {
    	for (i = 0 ; i < get_nb() ; i++)
    	{
    	    for (j = 0 ; j < get_node_number(0) ; j++)
    	    {
    		nodes_if_list[i][j] =1;
    	    }
    	}
        }
        return;
    }
    Et voici le soucis que j'ai a la compilation, avec gcc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    warning: passing arg 1 of 'save_nodes' from incompatible pointer type
    Comme vous le voyez avec le code commenté, lorsque j'écris directement dans mon tableau, tout fonctionne parfaitement. Le soucis ne survient que si j'appelle une fonction avec le tableau en paramètre.

    Est-ce que quelqu'un voit ou se situe mon problème, et saurait en plus me l'expliquer ?
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Peut être que ton compilo considère que int ** c'est par int[][]

    essaye en modifiant le prototype de ta fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void save_nodes (int nodes [][])
    Ceci dit, je n'ai pas plus d'explications
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre éclairé Avatar de sloshy
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2005
    Messages
    728
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Janvier 2005
    Messages : 728
    Points : 723
    Points
    723
    Par défaut
    Bonjour,
    en C90 le malloc des tableaux dynamique est obligatoire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*du code*/
        int **nodes;
        int count;
     
        nodes = malloc(sizeof(*nodes) * get_nb());
        for (count = 0; count <= get_nb(); count++)
            nodes[count] = malloc(sizeof(**nodes) * get_node_number(0));
        save_nodes(nodes);
    /*du code*/
    Bon c'est crade ici parce que je ne vérifie pas le retour du malloc, mais il ne devrait plus y avoir de warning.
    “La seule révolution possible, c'est d'essayer de s'améliorer soi-même, en espérant que les autres fassent la même démarche. Le monde ira mieux alors.”

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 685
    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 685
    Points : 30 974
    Points
    30 974
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Bonjour,

    Je m'essaye aux tableaux dynamiques avec le code suivant, mais j'ai visiblement un soucis que je ne trouve pas.

    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
     
    /* Pleins de choses avant */
     
    	    int nodes[get_nb()][get_node_number(0)];
     
    	    memset (nodes, 
    		    0, 
    		    get_nb() * get_node_number(0) * sizeof (int));
     
    /*	    DEBUGSTR1 ("Size : %lu", sizeof (nodes_if_lists)); */
    /*	    nodes_if_lists[1][1] = 12; */
    /*	    DEBUGSTR1 ("content : %d", nodes_if_lists[1][1]); */
     
    	    save_nodes (nodes);
     
    /* Pleins de choses apres */
    Salut

    Je n'ai pas touché au C depuis très longtemps et donc je ne suis pas au courant des dernières évolutions mais à mon époque, il était interdit de faire int tab[fonction_qui_retourne_une_valeur()] parce que le compilo avait absolument besoin d'un nombre connu à la compilation pour allouer la mémoire.
    Et donc fallait faire
    int *tab;
    tab=malloc(fonction_qui_retourne_une_valeur() * sizeof(int));

    Donc peut-être que le C99 a évolué pour accepter ton écriture, j'en sais rien. A vérifier...

    Citation Envoyé par gangsoleil Voir le message
    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
    /**
     * Save identifiers of all nodes
     * 
     *@param nodes : allocated list in which function will store data.
     *       
     *@return void
     *
     */
    void save_nodes (int ** nodes)
    {
        int i;
        int j;
     
        if (nodes != NULL)
        {
    	for (i = 0 ; i < get_nb() ; i++)
    	{
    	    for (j = 0 ; j < get_node_number(0) ; j++)
    	    {
    		nodes_if_list[i][j] =1;
    	    }
    	}
        }
        return;
    }
    Et voici le soucis que j'ai a la compilation, avec gcc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    warning: passing arg 1 of 'save_nodes' from incompatible pointer type
    Comme vous le voyez avec le code commenté, lorsque j'écris directement dans mon tableau, tout fonctionne parfaitement. Le soucis ne survient que si j'appelle une fonction avec le tableau en paramètre.

    Est-ce que quelqu'un voit ou se situe mon problème, et saurait en plus me l'expliquer ?
    Là c'est absolument normal. C'est un problème courant qui arrive aux débutants quand ils arrivent au pointeur et qu'il apprennent qu'un tableau est aussi un pointeur. Ils en déduisent qu'un tableau 2D est un pointeur de pointeur ce qui est logique... mais faux.

    L'équivalence tab[] <=> *pt n'est valable que pour la première dimension d'un tableau. Parce qu'en 1D, qu'on aille sur la case [n] ou qu'on aille sur la case située à *(pt + n) est identique. Dans tous les cas, le compilo décale de n positions.

    En 2D, ça ne marche plus pareil. Parce que la 2D n'est qu'une simulation mais le compilo continue à bosser en 1D. Et donc dans un int tab[y][x], aller sur la case [m][n] se traduira par un décalage de m * x + n. Mais ce décalage ne peut se faire que si le compilo connait la taille[x] de ton tableau.

    Et donc ta fonction save_nodes ne peut pas stocker ton tableau dans un int **. Parce que l'équivalence [] <=> * ne marche plus. Et si tu forces, ben ta fonction ne saura pas se déplacer dans le tableau.
    Ta fonction reçoit un int tab[y][x] qu'elle peut stocker dans un int nodes[y][x] ou un int *nodes[x] mais en aucun cas dans un int **nodes. Ce qui explique d'ailleurs ma remarque précédente à propos du compilo qui a besoin de connaitre la taille avant compilation...

    Ou alors tu travailles totalement en dynamique. Tu déclares alors un tableau de pointeurs, chaque pointeur étant alloué sur un tableau d'int. Ce n'est alors plus du tout de la 2D même si le comportement à l'exécution y ressemble...

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
        int **nodes;
        int i;
     
        // Allocation pour stocker tous les pointeurs
        nodes=malloc(get_nb() * sizeof(int *));
     
        // Allocation de chaque pointeur
        for (i=0; i < get_nb(); i++)
             nodes[i]=malloc(get_node_number(0) * sizeof(int));

    Et là, ta fonction save_nodes fonctionnera. Mais cet ersatz ci-dessus n'est pas parfait parce que dans la réalité, chaque retour de malloc doit être vérifié avec gestion particulière si un malloc échoue. Ce qui donne alors le code suivant
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    void free_nodes(int **nodes)
    {
        int i;
     
        if (nodes == NULL)
           return;
     
        for (i=0; i < get_nb() && nodes[i] != NULL; i++)
              free(nodes[i]);
        free(nodes);
    }
     
    fonction_principale()
    {
        // Plein de choses avant
     
        int **nodes;
        int i;
     
        // Allocation pour stocker tous les pointeurs
        nodes=malloc(get_nb() * sizeof(int *));
        if (nodes == NULL)
             return (code_particulier_qui_indique_pb);
     
        // Allocation de chaque pointeur
        for (i=0; i < get_nb(); i++)
        {
             nodes[i]=malloc(get_node_number(0) * sizeof(int));
             if (nodes[i] == NULL)
             {
                 free_nodes(nodes);
                 return (code_particulier_qui_indique_pb);
             }
        }
     
        // Travail sur nodes
        ...
     
        // Fin du travail - Libération mémoire
        free_nodes(nodes);
        return(code_particulier_qui_indique_reussite);
    }

    Comme tu vois, ça devient de suite une grosse galère à gérer. Hé oui, c'est ça le C. Tu comprendras que je préfère Python...
    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]

  5. #5
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Bonjour,

    Merci pour vos reponses.

    à mon époque, il était interdit de faire int tab[fonction_qui_retourne_une_valeur()] parce que le compilo avait absolument besoin d'un nombre connu à la compilation pour allouer la mémoire.
    Et donc fallait faire
    int *tab;
    tab=malloc(fonction_qui_retourne_une_valeur() * sizeof(int));

    Donc peut-être que le C99 a évolué pour accepter ton écriture, j'en sais rien.
    J'ai effectivement oublié de préciser que je travaillais en C99, qui autorise justement les tableaux dynamiques sans allocation mémoire spécifique. C'est d'ailleurs le seul but de ce bout de code.

    En gros, mon but était simplement d'utiliser cette spécificité de C99, et de voir comment ca se passait si je n'allouais pas la mémoire.

    J'essaierai demain en corrigeant le type de la fonction, et je vous dirai ce qu'il en est.

    Comme tu vois, ça devient de suite une grosse galère à gérer. Hé oui, c'est ça le C. Tu comprendras que je préfère Python...
    C'est pas une galère, c'est justement ce qui fait le charme de ce langage
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  6. #6
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Comme le dit Sve@r, le passage en argument d'un tableau 2D (ou plus) est embêtant en C.

    Pour un tableau, ce qui est passé est toujours l'adresse du premier élément du tableau. Si le tableau en argument est défini comme
    alors le paramètre doit être du type "adresse d'un tableau de M type", soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    type (*t)[M]// (avec les parenthèses obligatoires).
    // le C tolère aussi comme écriture pour le type du paramètre
    type t[][M]
    L'ennui est que tu dois spécifier M (pour la raison énoncée par Sve@r), ce qui alourdi si le tableau est un VLA (en C99), puisqu'il faut aussi passer la valeur de la dimension.
    Une autre possibilité est de le passer en tant que tableau 1D, mais la fonction devra faire le calcul des indices :
    Par exemple :
    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
     
    void fonc2(int i, int (*t)[i])
    {
      printf("%d", t[2][i-1]);
    }
    void fonc1(int i, int *t)
    {
      printf("%d", t[2*i+i-1]);
    }
    int main(void)
    {
      int i= 5;
      int j = i+2;
      int tab[i][j];
      tab[2][j-1] = 123;
      fonc2(j,tab);
      fonc1(j,tab[0]);
      return 0 ;
    }
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  7. #7
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 119
    Points
    28 119
    Par défaut
    Citation Envoyé par diogene Voir le message
    L'ennui est que tu dois spécifier M (pour la raison énoncée par Sve@r), ce qui alourdi si le tableau est un VLA (en C99), puisqu'il faut aussi passer la valeur de la dimension.
    C'est justement ce que je cherche a faire, mais je ne trouve pas de syntaxe correcte.

    En résumé :
    je sais que je peux utiliser un tableau alloué dynamiquement, mais je voulais essayer en utilisant les VLA.
    La déclaration du tableau ne pose pas de problème, mais je ne vois pas comment écrire le prototype de la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int save_nodes (int nodes[][])
    ne peut pas fonctionner, puisqu'il lui manque la taille du tableau (enfin la taille du second argument pour être précis)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int save_nodes (int nodes [][get_node_number(0)] )
    ne devrait pas passer non plus.

    J'en viens a me demander si on peut appeler une fonction en lui passant un VLA comme paramètre...
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  8. #8
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    On peut faire ça, mais je ne sais pas si ça répond à ton problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void fonc(int i, int (*t)[i]);
    void fonc(int i, int (*t)[i])
    {
      ....
    }
     
    int tab[dim1][get_node_number(0)];
    fonc(get_node_number(0),tab);
    Mais il serait mieux d'utiliser pour get_node_number(0) une variable intermédiaire plutôt que d'appeler plusieurs fois la fonction.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

Discussions similaires

  1. Appeler une fonction avec "action" ds un
    Par drinkmilk dans le forum ASP
    Réponses: 4
    Dernier message: 20/04/2004, 14h54
  2. Réponses: 4
    Dernier message: 19/04/2004, 13h41
  3. [JSP] Appeler une fonction
    Par Patrick95 dans le forum Servlets/JSP
    Réponses: 10
    Dernier message: 23/12/2003, 13h44
  4. Appel à des fonctions incluses dans des DLL
    Par Greybird dans le forum Langage
    Réponses: 3
    Dernier message: 26/05/2003, 13h33
  5. Appeler une fonction avec/sans parenthèses
    Par haypo dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 29/12/2002, 18h48

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