Programmation en C (pointeurs)

Répondre
Partager Rechercher
Salut à tous,

bon, voilà, j'ai quelques petits problèmes en C, là... les pointeurs, c'est vraiment pas mon fort... je m'embrouille tout le temps.

Enfin, je m'embrouille... tout dépend du style d'exercices, mais ici, j'ai un énoncé que je n'arrive pas du tout à résoudre... et je n'ai pas de solution.

L'un de vous saurait m'aider?

Code:
Quel sens donner à : 

int *p;
int **p;
int *p[10];
int (*p)[10];
int *p(void);
int *p(int *a);
int p (char *a[]);
int (*p)(char a);
int *(*p)(int *a);
Donc, en gros, il faut expliquer à quoi correspond ce qui est écrit plus haut.

pour le premier, c'est simple :

Initialisation d'un pointeur de type entier

mais alors, les autres, je sais plus.... j'ai bien sûr des idées, mais rien de sûr.


Quelqu'un saurait m'aider?

Merci
Re: Programmation en C (pointeurs)
int *p; --> p pointe vers un entier (*p renverra la valeur de l'entier)
int **p; --> p pointe vers un pointeur d'entier
int *p[10]; --> declare un tableau de pointeur, chaque pointeur du tableau pointe vers un entier
int (*p)[10]; --> heu je sais pas.. certainement la meme chose qu'au dessus
int *p(void); --> p est ici un pointeur de fonction (cette fonction ne prend pas de parametre et renvoie un entier)
int *p(int *a); --> p pointe vers une fonction qui recoit un pointeur d'entier en parametre (fin je suis pas sur)
int p (char *a[]); --> fichtre !
int (*p)(char a); --> diantre !
int *(*p)(int *a); --> erf
Re: Programmation en C (pointeurs)
Je te propose de chercher par toi meme, et seulement ensuite de regarder. Tu peux aussi le tapper dans un petit fichier C basique pour voir ce que dit le compilateur de tout ca, et pour essayer d'utiliser un peu les pointeurs qu'on te presente ici.
Code:
#include <stdlib.h>
#include <stdio.h>

int main(void)
{
  // ici une declaration 
 return EXIT_SUCCESS;
}
Il faut bien voir qu'un pointeur est quelque chose comme une indication de l'endroit ou se trouve une donnée, mais ne dit rien sur le contenu de la donnée elle meme. Regardes la semantique des operateurs * et & qui t'aideront certainement a comprendre mieux le sens de toutes ces choses. N'oublies pas non plus que la difference entre
Code:
 int a[]; int *b
n'est que conceptuelle et que finalement, a est du meme type que b.


Citation :
Provient du message de Lemuel
Salut à tous,

Code:
Quel sens donner à : 

int *p; // déclaration d'un pointeur sur un entier, pour l'instant le pointeur ne pointe sur rien. 
int **p; // déclaration d'un pointeur sur un pointeur d'entier, pour l'instant le pointeur ne pointe sur  rien.
int *p[10]; // déclaration d'un tableau de 10 pointeurs sur des entiers. L'espace memoire pour les 10 pointeurs est reservé mais ils ne pointent sur rien. 
int (*p)[10]; // declaration d'un pointeur sur un tableau de 10 int. En pratique c'est la meme chose que celui d'au dessus mais la verification de type n'est pas faite de la meme facon 
meme si les deux sont de type int** (essayes avec un code *p[0] = a; et p[0] = &a; pour voir la difference entre les deux) et l'allocation de la memoire statique n'est pas la meme. Un exemple bizare ca, j'aimerais que quelqu'un me confirme :monstre: 
int *p(void); // une fonction s'appelant p qui retourne un pointeur sur un entier. 
int *p(int *a); // une fonction s'appelant p qui retourne un pointeur sur un entier et prend un pointeur sur un entier en parametre. 
int p (char *a[]); // une fonction s'appelant p qui retourne un entier et prend un tableau de chaines de caracteres en parametre.
int (*p)(char a); // ca c'est un type et pas une declaration, le type designe un pointeur sur une fonction s'appelant p qui retourne un entier et prend un caractere en parametre
int *(*p)(int *a); // ca c'est un type et pas une declaration, le type designe un pointeur sur une fonction prenant un pointeur d'entier en parametre et retournant un pointeur d'entier.
mais alors, les autres, je sais plus.... j'ai bien sûr des idées, mais rien de sûr.


Quelqu'un saurait m'aider?

Merci
Merci a Corwin qui est le suel a avoir su detecter ma coquille en rouge (avant j'avais mis pointeur ce qui etait faux, vous faisiez quoi les autres vous dormiez, oui vous au fond la pres du radiateur ! )
Re: Programmation en C (pointeurs)
Citation :
Provient du message de Lemuel
[code]
Quel sens donner à :
je rapelle la définition de type en c :
truc machin; veut dire que machin est de type truc.

*machin désigne un déférencement de pointeur («la chose à l'adresse pointée par machin)

donc:
Citation :
int *p;
*p est de type entier, donc
p est pointeur vers un entier

[edit]mothra a raison, vaut mieux que tu cherches toi même [/edit]
[re-edit]ben en fait mothra a quand même donné la solution. Étant donné que se solution est juste, je remet pas ce que j'avais mis.[re-edit]
Pour lire , tu prends de droite a gauche , par exemple
int *p , ça se lit hop tu prends a droite , premier truc que tu trouves c'est p , alors tu commences la phrase par p , ensuite paf une étoile , pointeur ! et ça pointe sur quoi ? Sur le type , un entier ! Tu fais pareil avec les suivants , mais fais attention aux dernières déclarations , et surtout avec les parenthèses , si elles sont placées ne serait ce qu'un peu différemment cela peut avoir une tout autre signification.
Citation :
int *p[10]; // déclaration d'un tableau de 10 pointeurs sur des entiers. L'espace memoire pour les 10 pointeurs est reservé mais ils ne pointent sur rien.
int (*p)[10]; // declaration d'un pointeur sur un tableau de 10 int. En pratique c'est la meme chose que celui d'au dessus mais la verification de type n'est pas faite de la meme facon
meme si les deux sont de type int** (essayes avec un code *p[0] = a; et p[0] = &a; pour voir la difference entre les deux) et l'allocation de la memoire statique n'est pas la meme. Un exemple bizare ca, j'aimerais que quelqu'un me confirme
je vois pas ce qu'il y a de bizarre, et je confirme c'est un pointeur vers un tableau d'entiers
(pour le voir, *p est un tableau d'entiers)
pff chui nul en C la moitié de ce que j avais mis était faux ^^
mais bon j'ai fais ça pour remonter le post hein

au fait c jio qui post, pas vani, elle est bien meilleure que moi en C
Citation :
Provient du message de Lango Silma
je vois pas ce qu'il y a de bizarre, et je confirme c'est un pointeur vers un tableau d'entiers
(pour le voir, *p est un tableau d'entiers)
Oui, mais ce qui me tracasse c'est la facon dont est faite l'allocation statique de mémoire. Dans le cas 1 le compilo alloue dans la pile 10xsizeof(int *) et p pointe sur cet endroit, mais la je me demande ce qu'il alloue et ce que vaux p dans le second cas (j'ai testé ca ne segfault pas donc p a bien une valeur ce qui m'etonne).

La parole est a vous Lango
Citation :
Provient du message de Mothra
Oui, mais ce qui me tracasse c'est la facon dont est faite l'allocation statique de mémoire. Dans le cas 1 le compilo alloue dans la pile 10xsizeof(int *) et p pointe sur cet endroit, mais la je me demande ce qu'il alloue et ce que vaux p dans le second cas (j'ai testé ca ne segfault pas donc p a bien une valeur ce qui m'etonne).

La parole est a vous Lango
À ma connaissance le compilo n'alloue rien puisque p est un pointeur.
C'est pas pasque ça segfaulte pas que c'est bon, un pointeur qui vaut n'importe quoi peut tout à fait pointer dans une zone valide.

la preuve que non :
Code:
#define N 10

void init() {
   char buf[N];
   int i;
   for(i=0; i<N; i++)
      buf[i]=0;
}

void test() {
   int (*p)[10];
   *p[0]=1;
}

int main(){
   init();
   test();
   return 0;
}
ce programme segfaulte.
(pour les flemmards, je m'arrange juste pour être sur que la valeur non initialisée de p vaut bien 0).
Un pointeur non alloué vaut "a priori" NULL par defaut (a cause de la politique de sécurité du Kernel Linux qui te bzero les pages de mémoire quand il te les alloue). Et dereferencer NULL la sanction est immédiate
Ah super, merci!
En fait, les tableaux de pointeurs, j'en n'ai pas encore fait beaucoup... alors quand j'ai vu ce [10] derrière un pointeur, je me suis posé beaucoup de questions.

Et plus loin, évidemment, je suis tombé dans le piège... je n'avais pas remarqué que c'étaient des fonctions... tellement j'étais braqué sur mes pointeurs et mes déclarations...

Mais là, je pense avoir compris le truc, et à force de faire des exercices (heureusement, j'en ai qui sont corrigés), ça va rentrer!

Par contre, la différence entre

Code:
int *p[10];
et
int (*p)[10];
j'ai du mal de la saisir...
mais je pense qu'en sois, ça n'est pas très important (du moins pas encore à mon niveau).
Du moment que j'ai compris que c'était un tableau de 10 pointeurs qui pointaient vers des entiers... c'est ce qui compte je pense

encore merci à tous


[edit]
En fouillant mes cours, j'ai trouvé :

int *p[10] ->tableau de 10 pointeurs vers des entiers
int (*p)[10] -> un pointeur vers des tableaux de 10 entiers
Citation :
Provient du message de Lemuel
Par contre, la différence entre
Code:
int *p[10];
et
int (*p)[10];
j'ai du mal de la saisir...
mais je pense qu'en sois, ça n'est pas très important (du moins pas encore à mon niveau).
ben dis toi que
int *p[10] est équivalent à
int *(p[10])
ce qui se lit :
*(p[10]) est un entier
p[10] est un pointeur vers un entier
p est un tableau de 10 éléments de pointeurs vers des entiers

alors que
int (*p)[10]
se lit :
(*p)[10] est un entier
*p est un tableau de 10 entiers
p est un pointeur vers un tableau de 10 entiers.

Tu as raison, c'est pas évident à comprendre, mais une fois que tu auras fait la différence, les types en c n'auront plus de secrets pour toi

mothra : un pointeur fraichement alloué a pour valeur celle qui se trouvait sur la pile à l'emplacement qui lui est réservé... cet emplacement n'est pas forcément sur une page qui vient d'être allouée, donc pas nécéssairement à 0...
Tiens, un exercice interessant pour toi.

executes ce programme et commentes le resultat (si tu as des choses qui te tracassent demandes moi il est possible qu'il y ai des choses a priori inexplicables )

Code:
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  int a;
  int b;
  int *pa;
  char c;
  char tc[11];
  double d;
  double td[10];
  char cfin; 

  printf("sizeof(char)=%d\nsizeof(int)=%d\nsizeof(double)=%d\n", sizeof(char), sizeof(int), sizeof(double));
  printf("sizeof(char *)=%d\nsizeof(int *)=%d\nsizeof(double *)=%d\n", sizeof(char *), sizeof(int *), sizeof(double *));

  printf("&a=\t%p\n&b=\t%p\n&pa=\t%p\n", &a, &b, &pa);
  printf("&c=\t%p\n&tc=\t%p\n&d=\t%p\n&td=\t%p\n&cfin=\t%p\n", &c, &tc, &d, &td, &cfin);

 /* ajout pour attendre avant que la fenetre ne se referme */
 scanf("%c", &c);
  
  return EXIT_SUCCESS;
}
Que remarques tu en particulier pour pa et td, comment expliquer eventuellement les annomalies que tu remarques pour c et tc ? (si tu ne remarques pas d'anomalies n'hesites pas a poster, il est possible que sur ton architecture il n'y ai rien a voir pour c et tc )
Il y a un petit problème avec ce programme...
il n'accepte pas les
getch();

et moi, c'est la seule façon que j'ai trouvé pour que la fenêtre dos reste en place après avoir exécuté le programme... autrement, elle se ferme après avoir été exécutée... -> impossibilité de voir le résultat du programme.

Enfin bon, j'essaye déjà de le décoder comme ça
Citation :
Provient du message de Lango Silma
mothra : un pointeur fraichement alloué a pour valeur celle qui se trouvait sur la pile à l'emplacement qui lui est réservé... cet emplacement n'est pas forcément sur une page qui vient d'être allouée, donc pas nécéssairement à 0... [/i]
En effet, apparement lorsque le loader charge le fichier a exec la page est deja initialisée et contient deja du garbage et pas du 0 (je viens de tester). J'avais fait l'assertion incorrecte de penser que le nouveau programme etait lancé dans un page mallocée fraiche (tout ca est de toute facon tres implémentation dépendant, caitraimal de faire des choses comme ca ) .

Sinon apres verifications ca segfault bel et bien d'acceder a p déclaré de la seconde facon, conformement a ce que la declaration laisse penser (bon en fait ca segfault pas mais l'adresse est fantaisiste apres verification dans gdb) .
Citation :
Provient du message de Lemuel
Il y a un petit problème avec ce programme...
il n'accepte pas les
getch();

et moi, c'est la seule façon que j'ai trouvé pour que la fenêtre dos reste en place après avoir exécuté le programme... autrement, elle se ferme après avoir été exécutée... -> impossibilité de voir le résultat du programme.

Enfin bon, j'essaye déjà de le décoder comme ça
getch() n'est pas une fonction qui existe en C ANSI ou en C Posix, tu ne dois donc pas l'utiliser. Les bonnes fonctions sont getchar() et fgetc() qui sont fournies dans stdio.h
Voilà, trouvé un moyen de bloquer la fenêtre :

La première partie affiche la taille d'un caractère, d'un entier ou d'un double.

La seconde partie, je ne me souviens pas d'avoir vu des '*' à la fin de parenthèses... dnoc je ne vois pas...

La troisième partie, ça affiche les adresses des variables.

Par contre, j'ai du mal de répondre à tes questions...
Pour moi, des printf associés à des &, c'est écrire l'adresse de l'élément... mais c'est tout ce que je vois
Tu as vu juste dans la premiere partie
dans la seconde, je fais exactement la meme chose. Je te rapelle qu'on fait sizeof(type). Ici a la place de mettre int comme type, je met int * (pointeur sur un entier) et j'affiche la taille de ce type.

Pour la troisieme partie, en effet j'affiche les adresses des elements déclarés au dessus. Regardes ces adresses et la distance qui les separe et compares avec les sizeof des elements, tu devrais observer comment sont alloués les tableaux et les pointeurs que tu declares.
Citation :
Provient du message de Mothra
Pour la troisieme partie, en effet j'affiche les adresses des elements déclarés au dessus. Regardes ces adresses et la distance qui les separe et compares avec les sizeof des elements, tu devrais observer comment sont alloués les tableaux et les pointeurs que tu declares.
le problème c'est que l'allocation sur la pile est beaucoup plus compliquée qu'il n'y parait... il faut penser à plein de trucs, dont le fait que la pile est découpée par blocs de 4 octets, ce qui fait que des fois on a des blancs de quelques octets entre 2 variables. d'ailleurs j'ai regardé je comprends pas tout, la politique d'allocation a l'air de différer pour tableau et non-tableau... (tc est un octet plus bas que j'aurais pensé), et j'ai un trou ce 4 octects entre d et tc

Comme Lemuel ne doit pas maitriser ce qu'est la pile (si déjà il a vu ce que c'était...) je lui conseille d'oublier tout ça
Ca n'est pas la pile qui est decoupée en bloc de 4, c'est le compilateur qui aligne les instructions et les données sur 4 octets pour accelerer l'execution. Ca n'est pas tres compliqué et je trouve au contraire qu'il est bon de savoir ce qui se passe quand on declare deux trois entiers et 4 5 pointeurs. Ca permet de comprendre pourquoi le programme plante mysterieusement dans un printf qui n'a rien a voir ou des choses extremement puzzlante autrement
J'ai plus ou moins compris certains trucs

pour a (entier), j 'ai comme adresse : 0012FF88
pour b (entier), j'ai comme adresse : 0012FF84 (décalé de 4 bits apparemment, par rapport à a... la longueur d'un entier)

pa, comme adresse : 0012FF80
mais je comprends pas comment ça se fait

c (char) a comme adresse : 0012FF7F
d (double) a comme adresse : 0012FF74
mais j'aurais crû qu'il aurait eu une adresse décalée de 8 bits, et pas de 12...
Il y a tc aussi entre les deux, ce qui rajoute 11 bytes (+1 de c) ce qui donne bien les 12 attendus. Relances le programme en declarant tc[12] a la place de tc[11]. Tu devrais observer le fameux alignement a 4. A la place de prendre 1 octet comme normal, le denier char du tableau va en prendre 4 (en fait 1 utile pour la valeur et 3 de bourage pour respecter l'alignement).
Pour garder une fenêtre DOS active après avoir exécuté quelquechose, tu faire un "system pause" ça marche aussi très bien...
Il attendra que tu tape sur une touche pour continuer à dérouler ...

Euh, par contre, la nuance entre int (*p)[10] et int *p[10], mais j'ai pas de meilleure explication que celle de ton cours (c'est celle-là à laquelle j'avais pensé ), je l'ai bien saisie personnellement...

Et euh sinon, pour avoir fait tourné un débugger plusieurs fois, je peux assurer que la valeur d'un pointeur est totalement aléatoire si on ne l'initialise pas.
Citation :
Provient du message de Mothra
Ca n'est pas la pile qui est decoupée en bloc de 4, c'est le compilateur qui aligne les instructions et les données sur 4 octets pour accelerer l'execution.
2 façons différentes de dire la même chose...

Citation :
Provient du message de Mothra
Ca n'est pas tres compliqué et je trouve au contraire qu'il est bon de savoir ce qui se passe quand on declare deux trois entiers et 4 5 pointeurs. Ca permet de comprendre pourquoi le programme plante mysterieusement dans un printf qui n'a rien a voir ou des choses extremement puzzlante autrement
c'est pas compliqué quand tu l'as vu en cours. Et que tu as eu le temps d'y réfléchir souvent...
Ce n'est pas le plus important à maitriser pour bien programmer en c. D'ailleurs la position exacte dans la pile n'est pas spécifiée dans la norme c et est au choix du compilateur.
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés