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 :

"new" exécuté ou pas ?


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Mars 2004
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Mars 2004
    Messages : 150
    Par défaut "new" exécuté ou pas ?
    Bonjour à tous,

    Dans nombreux de mes programmes je définis des tableaux dont j'ignore a priori la taille par "int *tableau" et lorsque je connais la taille j'écris tableau=new int[taille]. Je pense que c'est très classique.

    Je voudrais savoir comment faire pour savoir avant de créer ce tableau s'il n'a pas par hasard déjà été créé. J'ai bien essayé de regarder la valeur de &tableau qui est NULL avant de définir le tableau par "new" et une adresse semble-t-il non nulle lorsque le tableau a déjà été défini, mais je ne sais pas si c'est très orthodoxe car n'est-il pas possible que l'adresse affectée par "new" soit justement 0 ?

    Merci d'avance pour tout conseil.

  2. #2
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    La fonction ou l'opérateur d'allocation te retourne zéro en cas d'échec seulement. Une telle adresse est invalide.

    Cela dit, il y a confusion :
    • new [] c'est du C++, en C c'est malloc ;
    • NULL c'est du C, en C++ c'est nullptr ;
    • on évite en général de manipuler directement des tableaux en C++, et sauf cas d'utilisation spécifique on préfère std::array et std::vector selon que l'on en connaisse la taille à la compilation ou à l'exécution.

    Que cherches-tu à faire ? En quel langage ? Peux-tu nous monter un exemple ?

  3. #3
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Mars 2004
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Mars 2004
    Messages : 150
    Par défaut
    Merci de ta réponse.

    Pour clarifier un peu le débat, je me présente. Je suis un programmeur du passé (!). J'ai travaillé des dizaines d'années en Fortran, bien avant l'avènement du C, et je me suis mis au C il y a quelques années mais sans avoir jamais reçu de cours, ni en C, ni en C++. D'où des questions parfois de débutant.

    J'utilise Microsoft Visual Studio 2010, Version 10.0.40219.1 SP1Rel (Microsoft Visual C++ 2010 01013-169-2610014-70286), que j'ai téléchargé gratuitement sur mon PC. En fait, par ignorance, il me semble que je n'utilise que du C… mais il s'agit bien d'un compilateur C++ !

    Le mot NULL est utilisé couramment dans cette version.

    De même que "new". J'ai trouvé cette instruction intéressante pour me créer des tableaux dont la dimension était inconnue à la compilation, et également pour créer de gros tableaux dans une autre partie de la mémoire. Je ne connais pas "malloc" ni "std::array", ni "std::vector"

    Pour revenir à ma question, pendant l'exécution de mon programme je crée un tableau à deux dimensions, préalablement défini à la compilation par "unsigned char **ima" par :

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void creima(int nblig,int nbcol)
    {
       ima = new unsigned char*[nblig]; // ETAPE 1: INITIALISE LES LIGNES.
          for (int j = 0; j < nblig; j++)
              ima[j] = new unsigned char[nbcol]; // ETAPE 2: INITIALISE LES COLONNES
    }

    Mais avant de faire cela, je voudrais m'assurer que cela n'a pas déjà été fait. Il me semble que créer deux fois un tableau avec le même nom ne pourrait conduire qu'à des résultats catastrophiques. Donc, je me demandais si je pouvais savoir si ima a déjà été créé ou non, en testant justement ima. J'ai constaté que tant que je n'ai pas créé ima par "new", l'adresse &ima était égale à zéro, c'est-à-dire NULL, et qu'au contraire, une fois que ima a été créé, &ima est une adresse non nulle, précisément l'adresse de début de mon tableau.

    C'est tout !

    on évite en général de manipuler directement des tableaux en C++
    Qu'entends-tu par manipuler des tableaux ? Et si l'on évite ça, que fait-on à la place ?

    Merci en tous cas de ton aide.

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 769
    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 769
    Par défaut
    Tu peux paramétrer ton Visual pour compiler en C: il faudra vérifier mais clic droit sur un fichier .c : ... -> C/ C++ -> Advanced -> Compile As

    Après avec ton new tu vas rigoler , surtout que ce n'est même pas du C99 (tu vas devoir définir tes variables en premier dans un bloc)


    Ensuite, ima c'est un pointeur: il contient une adresse. Il ne faut pas tester &ima mais ima.

    Et justement, en C, la première chose qu'on fait après la définition c'est de mettre le pointeur à NULL ima = NULL;.

    Ainsi, on sait s'il a été modifié ou pas if (ima != NULL) { /*iam is modified*/ }.

    Sinon, on ne peut pas le savoir. Peut-être pas en mode debug, mais une variable contient toujours du "random" au début.

  5. #5
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Ok, il y a pas mal à dire.


    De ce que tu nous écris, tu ne connais ni le C, ni le C++. Sans compter les petites méconnaissances techniques, tu baragouines un dialecte hybride qu'il serait mal avisé d'utiliser pour un nouveau projet. Il te faut donc apprendre un (et pour commencer un seul) langage et t'y tenir jusqu'à ce que tu sois à l'aise pour t'exprimer librement. C'est un peu comme l'apprentissage d'une langue étrangère, sauf qu'un langage de programmation est un outil donc intrinsèquement plus ou moins adapté à ce que l'on veut réaliser.

    C'est pourquoi avant de t'orienter la première question que je te poserai est celle-ci : que veux-tu faire ? As-tu un projet en tête ? Ou est-ce que tu veux simplement apprendre à programmer un ordinateur moderne ?


    Citation Envoyé par ceugniet Voir le message
    J'utilise Microsoft Visual Studio 2010, Version 10.0.40219.1 SP1Rel (Microsoft Visual C++ 2010 01013-169-2610014-70286), que j'ai téléchargé gratuitement sur mon PC. En fait, par ignorance, il me semble que je n'utilise que du C… mais il s'agit bien d'un compilateur C++ !
    Précisons bien une chose : le C et le C++ sont deux langages différents. Il ne faut ni les mélanger, ni les interchanger. Je ne vais pas te faire l'histoire des deux langages, d'autres dont Wikipédia la récitent bien mieux que moi. La confusion vient du fait que C++ ayant été historiquement conçu autour de C, beaucoup de constructions sont identiques et certains programmes C sont acceptés tels quels par les compilateurs C++. Les deux langages évoluant indépendamment, c'est de moins en moins vrai et tant mieux.

    Lorsque l'on programme dans un langage donné, il est d'usage de respecter la norme à savoir un ensemble de règles et de contraintes définies pour assurer un minimum d'interopérabilité entre les nombreuses implémentations du langage (une norme, quoi..). Les dernières normes publiées sont C11 pour le langage C (2011) et C++14 pour le langage C++ (2014), avec C++17 déjà bien avancée.

    Inutile de te dire que le compilateur fourni avec VS 2010 est obsolète pour les deux langages (particulièrement le C dont la prise en charge par les compilateurs Microsoft est historiquement très mauvaise jusqu'au moins VS 2012). Tu dois mettre à jour ton compilateur à la version la plus récente compatible avec ton OS, en l'occurrence VS 2015 si tu désires continuer à utiliser Visual Studio (je crois que la Community Edition est gratuite). Il existe autrement plein d'autres toolchains, dont GCC et Clang. Pelles C est également une bonne alternative - bien qu'exotique - sous Windows.


    Pour en revenir à ta question technique, je n'ai pas tout saisi mais le langage te garantit que l'adresse renvoyée par l'allocateur est soit invalide (et aisément testable comme telle) en cas d'échec, soit valide et unique : elle n'a pas été attribuée auparavant (sauf sérieux bug du kernel ). La responsabilité de stocker cette adresse dans une variable te revient. Si tu écrases la valeur d'une adresse déjà attribuée auparavant et stockée dans la même variable, alors la référence vers le bloc alloué est perdue : si tu ne l'as pas dupliquée quelque part, il n'y a aucun moyen de la rendre au système et de récupérer ainsi l'espace mémoire associé. Déterminer si c'est catastrophique ou pas dépend de l'application (s'il s'agit d'un serveur web qui doit pouvoir tourner 24/7 oui, ça l'est probablement car le processus épuisera la quantité de mémoire disponible).

    Note également qu'il est invalide ne serait-ce que de consulter la valeur d'un pointeur non initialisé ou dont l'adresse a été restituée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int *p = NULL;
    if (p) // ok
        /* ... */
     
    p = malloc(1 * sizeof(*p));
    if (p) { // ok
        free(p);
        if (p) // /!\ comportement indéterminé
            /* ... */
    }
     
    int *q;
    if (q) // /!\ comportement indéterminé
        /* ... */
    Tu peux en déduire que la seule valeur d'adresse invalide et testable est NULL (nullptr en C++). On s'en sert donc naturellement pour identifier les pointeurs libres dans une structure.


    Citation Envoyé par ceugniet Voir le message
    Qu'entends-tu par manipuler des tableaux ? Et si l'on évite ça, que fait-on à la place ?
    On reviendra aux spécificités une fois les bases acquises, si tu le veux bien.

  6. #6
    Membre confirmé
    Homme Profil pro
    Retraité
    Inscrit en
    Mars 2004
    Messages
    150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Mars 2004
    Messages : 150
    Par défaut
    Merci à tous pour vos explications détaillées. J'en prend note.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Par déduction de ce que dit Matt_Houston, on se rend compte qu'il convient alors de toujours s'assurer que chaque pointeur ne puisse avoir que deux types de valeurs différentes:
    • soit une valeur valide,
    • soit NULL (en C) ou nullptr (en C++).

    Cela peut être fait en les initialisant systématiquement dès qu'on les déclare où qu'on construit une structure qui en contient un (ce qui en C, peut être fastidieux dans le cas de tableaux; ça tend à être plus facile en C++).
    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.

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

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