Pointent vers le même objet mais la modification de l'un n'entraine pas la modif

[Résolu]
Signaler
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008
-
Messages postés
475
Date d'inscription
jeudi 19 juin 2003
Statut
Membre
Dernière intervention
3 novembre 2008
-
Dans un tutorial, j'ai le programme suivant :


void Main(
string[] args)
{

// lecture des éléments d'un tableau tapés au clavier
Boolean terminé =
false;

int i = 0;

double[] éléments1 =
null;

double[] éléments2 =
null;

double élément = 0;

string réponse =
null;

Boolean erreur =
false;



while (!terminé)
{

// question
Console.Out.Write(
"Elément (réel) " + i +
" du tableau (rien pour terminer) : ");

// lecture de la réponse
réponse =
Console.ReadLine().Trim();

// fin de saisie si chaîne vide
if (réponse.Equals(
""))
break;

// vérification saisie
try
{
élément =
Double.Parse(réponse);
erreur =
false;
}

catch
{

Console.Error.WriteLine(
"Saisie incorrecte, recommencez");
erreur =
true;
}
//try-catch



// si pas d'erreur
if (!erreur)
{

// un élémt de plus dans le tableau
i += 1;

// nouveau tableau pour accueillir le nouvel élément
éléments2 =
new
double[i];

// copie ancien tableau vers nouveau tableau
if (i != 1)
Array.Copy(éléments1, éléments2, i - 1);

// nouveau tableau devient ancien tableau
éléments1 = éléments2;

// plus besoin du nouveau tableau
éléments2 =
null;

// insertion nouvel élément
éléments1[i - 1] = élément;
}
//if


}
//while



// affichage tableau non trié
System.
Console.Out.WriteLine(
"Tableau");

for (i = 0; i < éléments1.Length; i++)
Console.Out.WriteLine(
"éléments[" + i +
"]=" + éléments1[i]);

}

ce qui m'étonne est que les tableau éléments1 et éléments2 appartenant à la même classe, quand on fait :
éléments1 = éléments2;
on les fait pointer vers le même objet.


Alors quand on fait :
éléments2 = null;


on devrait avoir aussi éléments1 = null; non ?
visiblement ce n'est pas le cas. Pourriez vous m'indiquer pourquoi ?

merci

mathmax

15 réponses

Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
L'opérateur ( * ) s'utilise comme ça :


int i = 0;
int* p = &i; // p pointe sur i*p 10; // i 10


Il y'a 2 opérateurs pour acceder aux membres d'un objet, le point ( . ) et ( -> ) qui indique bien qu'il s'agit de pointer sur l'objet.


p->age = 20;


Y'a qu'un cours en C qui pourra t'expliquer toutes les subtilités sur les pointeurs, on peut utiliser ces opérateurs en C# mais uniquement dans un context unsafe, faut compiler avec l'option unsafe et déclarer la classe ou la fonction unsafe ou juste un bloc :


unsafe
{
// ..
}
Messages postés
475
Date d'inscription
jeudi 19 juin 2003
Statut
Membre
Dernière intervention
3 novembre 2008
1
utiliser les pointeurs n'est pas recommandé.
c'est pas pour rien qu'on les marque unsafe.
Un mauvais usage pourra occasioner des erreurs graves de l'application.
Je vais p-e dire une connerie mais je pense que le CLR ne peut pas gérer des erreurs occasionnés par un pointeur.

Si je me trompe, corrigez-moi :)

@++
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
37
nan... en fait... elements1 et elements2 sont des pointeurs vers un même objet.
donc, quand tu fais : elements2 = null... tu fais pointé elements2 dnas le vide.


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

Ok on est donc dans un cas particulier où quand on fais pointer element2 dans le vide, element1 ne "suit" pas. Mais si on avais donné à element2 une valeur de type string[], alors element1 aurait automatiquement pointé vers cette valeur (objet), non ?


Mathmax
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
37
non, car elements1 et elements2 sont 2 pointeurs différents


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

Je ne comprends pas. Tu m'as dis "elements1 et elements2 sont des pointeurs vers un même objet" et "elements1 et elements2 sont 2 pointeurs différents". N'est-ce pas contradictoire ?
Pointent t-ils vers le même objet ? Si oui, je ne vois pas pourquoi la modification de l'un n'entraine pas la modification de l'autre.


Mathmax
Messages postés
475
Date d'inscription
jeudi 19 juin 2003
Statut
Membre
Dernière intervention
3 novembre 2008
1
Admettons que t'as deux tubes qui débouchent dans un même égout. tu peux donc utiliser n'importe lequel des deux tubes pour te jeter dans l'égoût. Appellons-les tube 1 et 2. Si jamais tu bouche le tube 2, tu serais tjrs capable de te jeter dans l'égoût à partir du tube 1.


(quel mauvais exemple )

Alors, dans ton cas, t'as deux pointeurs différents, totalement indépendants, qui représentent deux chemins pour acceder à ton objet. Si le deuxième pointeur est "bouché" avec une valeur null, tu pourras tjrs utiliser ton premier pointeur.

C'est drôle de voir que la notion de pointeur (int* ptr) a disparu avec le C# (du moins, en code safe) mais que la notion de variable qui font référence à des objets (un genre de pointeur) est tjrs existante.

En tout cas, j'espère que c'est plus clair.

@++
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Salut, en C# on parle de références mais en fait il s'agit d'un pointeur ( mais on ne peut pas le manipuler comme un vrai pointeur ), il faut comprendre qu'un pointeur c'est une variable qui contient l'adresse mémoire d'une autre variable : ) cette adresse par exemple si elle vaut 0x8000 quand tu passes la référence à null c'est cette adresse qui devient 0x0000 et la référence pointe sur rien du tout et c'est pas l'objet pointé qui devient null.


Un petit schéma piqué sur la MSDN :


http://msdn.microsoft.com/vstudio/art/javarc/csharpforjava_fig02.gif
Messages postés
80
Date d'inscription
mercredi 6 octobre 2004
Statut
Membre
Dernière intervention
26 septembre 2006

Je vais essayer d'expliquer de façon complémentaire :

Ce n'est pas du tout un cas particulier (ou plutôt, c'est le cas de TOUT SAUF les types simples tel int, char, byte, ...). Ici, il s'agit d'un tableau.

// Création de références de type "référence vers un tableau de double"

double
[] éléments1 =
null;

double[] éléments2 =
null;

//
On fait pointer la référence éléments2 vers un nouvel objet qu'on crée ici (à l'aide du mot clé new). Il s'agit d'un objet de type "tableau de 10 double)

éléments2 =
new
double[10];

//
On copie la référence "élément2" vers "élément1" (Référence, pas de copie d'objet). On a toujours un seul objet.

éléments1 = éléments2;

//
On fait pointer "élément2" vers le vide. On ne touche pas à l'objet tableau ni à la référence "éléménts1"
éléments2 =
null;

Le seul moyen de toucher aux éléments du tableau, et de manipuler les variables élements1[0] à élements1[9] .

autre exemple :

double
[] éléments1 =
null;

double[] éléments2 =
null;

//
Ici, éléments1 et éléments2 pointent vers 2 objets différents
éléments2 =
new
double[10];

éléments1 =
new
double[10];


//
On fait pointer "élémént2" vers l'objet qui est pointé par "élément1"

éléments2 =
éléments1 ;

Remarque : Après cette instruction, l'ancien objet qui était pointé par "élément2" est détruit. En effet, il n'y a plus moyen d'accéder à l'objet, donc il automatiquement détruit.

En espérant avoir répondu à tes attentes

Nico
Strasbourg
France
Messages postés
80
Date d'inscription
mercredi 6 octobre 2004
Statut
Membre
Dernière intervention
26 septembre 2006

Encore un truc....
Pour de très bons cours de programmation : www.developpez.com

C'est un site de référence pour tous les languages.

Nico
Strasbourg
France
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
37
je reviens sur la remarque :
Remarque : Après cette instruction, l'ancien objet qui était pointé par "élément2" est détruit. En effet, il n'y a plus moyen d'accéder à l'objet, donc il automatiquement détruit.

En réalité, l'objet n'est pas immédiatement, il vit encore quelques instant dans la mémoire le temps que le GAC passe.

Pour résumé, C# n'utilise pas implicitement les notations *, & et -> comme le C/C++, mais en réalité c'est la même chose.
Ecrire C# :
double[] tabDouble;
List<string> strCollection = new List<string>();
strCollection.Add("toto");

Reviens à écrire en C++:
double[] *tabDouble;
List<string> *strCollection = new List<string>();
*strCollection->Add("toto");


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
54
J'ajouterais, meme si c'est pas le theme de la discussion, qu'il faut eviter les variables avec des accents dedans



Mx
MVP C#
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

Tous me parait logique dans vos réponses, mais pourtant dans cet exemple la modification d'une référence, entraîne automatiquement la modification de l'autre. Pourquoi ? N'est -on pas dans le même cas que précédement avec deux instance d'une même classe ? Voici le programme :

// classe PERSONNE
class PERSONNE{
public string nom;
public int age;
}

// une PERSONNE P1
PERSONNE P1=
new PERSONNE();
P1.nom=
"paul";
P1.age=10;

Console.Out.WriteLine(
"P1=PERSONNE("+P1.nom+
","+P1.age+
")");



// une PERSONNE P2
PERSONNE P2=P1;

Console.Out.WriteLine(
"P2=PERSONNE("+P2.nom+
","+P2.age+
")");



// P2 est modifié
P2.nom=
"nicole";
P2.age=30;



// vérification P1 et P2
Console.Out.WriteLine(
"P1=PERSONNE("+P1.nom+
","+P1.age+
")");

Console.Out.WriteLine(
"P2=PERSONNE("+P2.nom+
","+P2.age+
")");

//P1 à lui été modifié.

On obtiens les résultats suivants :

P1=PERSONNE(paul,10)
P2=PERSONNE(paul,10)
P1=PERSONNE(nicole,30)
P2=PERSONNE(nicole,30)


Mathmax
Messages postés
3246
Date d'inscription
lundi 25 avril 2005
Statut
Modérateur
Dernière intervention
27 octobre 2012
41
Tu as utilisé l'opérateur point ( . ) ce n'est donc pas la référence que tu modifies mais l'objet pointé, pour bien comprendre faudrait que tu étudis en C l'opérateur de "déréférenciation" ( * ).
Messages postés
403
Date d'inscription
vendredi 28 octobre 2005
Statut
Membre
Dernière intervention
31 août 2008

Ok tu veux dire que par l'opérateur (.) j'ai modifié les valeurs des attributs de l'objet ? Normalement si j'avias écris P2*nom="nicole", j'aurais juste modifié la référence ? J'ai testé ça chez moi, ça me signale une erreur. Est-ce un opérateur propre à C ? Y a t-il un équivalent en C# ?


Mathmax