Passer des pointeurs / références à des structures dans des fonctions
Cela va sembler une question stupide, mais je suis encore à apprendre le C, donc s'il vous plaît garder avec moi. 🙂
Je suis en train de travailler sur le chapitre 6 de K&R (struct), et à ce jour à travers le livre, ont connu un grand succès. J'ai décidé de travailler avec des structures assez fortement, et n'a donc beaucoup de travail au début du chapitre, le point et rect exemples. L'une des choses que je voulais faire était de changer la canonrect
fonction (2e Édition, p 131) de travail via des pointeurs, et donc de retour void
.
J'ai ce travail, mais a couru dans un hoquet, j'ai été en espérant que vous les gars pourrait m'aider avec. Je voulais canonRect
pour créer un temporaire de l'objet rectangle, effectuer ses modifications, puis réaffecter le pointeur passé à la temporaire rectangle, ce qui permettra de simplifier le code.
Cependant, si je fais ça, le rect ne change pas. Au lieu de cela, je me retrouve manuellement repeupler les domaines de la rect je suis passé de, qui ne de travailler.
Le code suivant:
#include <stdio.h>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
struct point {
int x;
int y;
};
struct rect {
struct point lowerLeft;
struct point upperRight;
};
//canonicalize coordinates of rectangle
void canonRect(struct rect *r);
int main(void) {
struct point p1, p2;
struct rect r;
p1.x = 10;
p1.y = 10;
p2.x = 20;
p2.y = 40;
r.lowerLeft = p2; //note that I'm inverting my points intentionally
r.upperRight = p1;
printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n",
r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);
//can't pass a pointer, only a reference.
//(Passing pointers results in illegal indirection compile time errors)
canonRect(&r);
printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n",
r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);
}
void canonRect(struct rect *r) {
struct rect temp;
temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);
r = &temp; //doesn't work; my passed-in rect remains the same
//I wind up doing the following instead, to reassign all
//the members of my passed-in rect
//r->lowerLeft = temp.lowerLeft;
//r->upperRight = temp.upperRight;
}
Donc voici les questions:
- Pourquoi ne
r = &temp;
pas de travail? (Je pense c'est parce que je passe dans une référence au lieu d'un pointeur; ai-je raison de penser que les références ne sont pas modifiés, mais les pointeurs sont?) - Pourquoi pourrais-je obtenir un acte illégal d'indirection erreur de compilation si j'essaie de passer un pointeur vers
canonRect
? (C'est à dire, si j'avaiscanonRect(*r);
dansmain()
.)
Je pense que je connais déjà la réponse à #1, #2 confond moi -- j'ai pensé qu'il était légal de passer des pointeurs autour de.
De toute façon ... veuillez pardonner le C newb.
source d'informationauteur John Rudy
Vous devez vous connecter pour publier un commentaire.
Je pense que ce que vous voulez faire est ceci:
Dans le code ci-dessus vous sont *r, qui est de type rect à la température qui est de type rect.
Re 1: Si vous voulez changer ce qui r vers vous besoin d'utiliser un pointeur vers un pointeur. Si c'est vraiment ce que vous voulez (voir ci-dessus, il n'est pas vraiment ce que vous voulez) vous devrez alors assurez-vous de pointer vers quelque chose sur le tas. Si vous pointez quelque chose de pas créé avec les "nouveaux" ou malloc puis il va tomber hors de la portée et de vous pointer à la mémoire qui n'est plus utilisé pour cette variable.
Pourquoi ne pas votre code de travail avec r = &temp?
Car r est de rect* type. Cela signifie que r est une variable qui contient une adresse mémoire qui est de la mémoire contient un rect. Si vous changez ce que r est de pointage, c'est bien, mais cela ne change pas le passé en variable.
Re 2: * lorsqu'il n'est pas utilisé dans une déclaration de type est le déréférencement de l'opérateur unaire. Cela signifie qu'il va rechercher ce qui est à l'intérieur de l'adresse du pointeur. Donc, en passant *r vous n'êtes pas en passant un pointeur à tous. En face puisque r n'est pas un pointeur, c'est une syntaxe non valide.
Il est aussi intéressant de noter votre variable 'struct rec temp', aller hors de portée dès que cette méthode canonRect se termine et vous sera orienté vers une mémoire non valide.
On dirait que vous vous êtes confus le "déréférencement" opérateur (
*
) avec l " adresse de l'opérateur (&
).Lorsque vous écrivez
&r
qui obtient l'adresse de la r et retourne un pointeur vers r (un pointeur est une adresse mémoire d'une variable). Si vous êtes vraiment en passant un pointeur dans la fonction.Lorsque vous écrivez
*r
vous essayez de déréférencer r. Si r est un pointeur, qui sera de retour la valeur de r est de pointage. Mais r n'est pas un pointeur, c'est un rect, de sorte que vous aurez une erreur.Pour rendre les choses plus confuses, le
*
de caractère est également utilisé lors de la déclaration de pointeur de variables. Dans cette déclaration de fonction:r
est déclaré être un pointeur sur unstruct rect
. C'est complètement différent de l'utilisation de*
comme ceci:Dans les deux cas, le caractère * signifie quelque chose de complètement différent.
Premier, K&R c n'ont pas de concept de "références", juste des pointeurs. Le
&
opérateur signifie "prendre l'adresse de".Deuxièmement, la
r
danscannonRect()
est une variable locale, et est pas lar
dansmain()
. La modification de l'emplacement du localr
points n'a pas d'effet sur lesr
dans l'appel de la routine.Enfin, comme l'a déjà noté le local
struct rect
est alloué sur la pile, et sort du champ à l'accolade fermante,Vous voudrez peut-être lire sur les différentes façons de paramètres peuvent (théoriquement) être transmis à des fonctions. C est appel-par-valeurde sorte que lorsque vous passez le pointeur de votre souris un rectangle dans la fonction de transmettre une copie du pointeur. Toute modification de la fonction à la valeur de r directement (pas indirectement) ne sera pas visible à l'appelant.
Si vous souhaitez que la fonction de fournir à l'appelant une nouvelle structure alors il y a deux façons de le faire:
1. vous pouvez revenir à une rect:
2. vous pouvez passer un pointeur vers un pointeur vers un rect:
La première manière serait plus naturel:
La deuxième voie serait:
et l'appelant alors utiliser:
Mais l'appelant perd original pointeur il avait, et vous devez être prudent de ne pas fuir les structures.
Quelle que soit la technique que vous utilisez, la fonction aura besoin d'allouer de la mémoire pour la nouvelle structure sur le tas à l'aide de malloc. Vous ne pouvez pas allouer de l'espace sur la pile en déclarant simplement une struct parce que la mémoire devient invalide lorsque la fonction retourne.
Parce que, il n'est pas le but de pointeur.