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

Résolu
cs_mathmax Messages postés 403 Date d'inscription vendredi 28 octobre 2005 Statut Membre Dernière intervention 31 août 2008 - 10 févr. 2006 à 19:52
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 - 11 févr. 2006 à 19:15
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

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 42
11 févr. 2006 à 19:03
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
{
// ..
}
3
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 1
11 févr. 2006 à 19:15
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 :)

@++
3
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 38
10 févr. 2006 à 20:45
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#]
0
cs_mathmax Messages postés 403 Date d'inscription vendredi 28 octobre 2005 Statut Membre Dernière intervention 31 août 2008
10 févr. 2006 à 21:20
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
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 38
10 févr. 2006 à 22:32
non, car elements1 et elements2 sont 2 pointeurs différents


Sébastien FERRAND (
blog)
[Microsoft MVP Visual C#]
0
cs_mathmax Messages postés 403 Date d'inscription vendredi 28 octobre 2005 Statut Membre Dernière intervention 31 août 2008
10 févr. 2006 à 22:48
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
0
cs_badrbadr Messages postés 475 Date d'inscription jeudi 19 juin 2003 Statut Membre Dernière intervention 3 novembre 2008 1
10 févr. 2006 à 23:02
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.

@++
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 42
10 févr. 2006 à 23:25
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
0
nico_fip1 Messages postés 80 Date d'inscription mercredi 6 octobre 2004 Statut Membre Dernière intervention 26 septembre 2006
11 févr. 2006 à 10:06
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
0
nico_fip1 Messages postés 80 Date d'inscription mercredi 6 octobre 2004 Statut Membre Dernière intervention 26 septembre 2006
11 févr. 2006 à 10:09
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
0
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 38
11 févr. 2006 à 10:24
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#]
0
MorpionMx Messages postés 3466 Date d'inscription lundi 16 octobre 2000 Statut Membre Dernière intervention 30 octobre 2008 57
11 févr. 2006 à 11:02
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#
0
cs_mathmax Messages postés 403 Date d'inscription vendredi 28 octobre 2005 Statut Membre Dernière intervention 31 août 2008
11 févr. 2006 à 13:28
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
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 42
11 févr. 2006 à 14:16
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" ( * ).
0
cs_mathmax Messages postés 403 Date d'inscription vendredi 28 octobre 2005 Statut Membre Dernière intervention 31 août 2008
11 févr. 2006 à 17:57
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
0