Algorithmque et programmation

Fermé
demandeuse - 19 mars 2009 à 22:25
mamiemando Messages postés 33591 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 mars 2025 - 25 mars 2009 à 01:33
Bonjour,
J'ai envoyé ma réponse pendant deux jours mais vous m'avez pas répondu à ma question SVP essayez le maximum possible à m'envoyez la réponse à trés bientôt car vraiment j'ai une grande difficulté concernant le pointeur et surtout sur le forçage et les opérations SVP vous êtes le seul et le dernier espoir et la dernière solution que j'ai trouvé enfin en cherchant sur la toile car avant je connue pas ce forum .

DONC:
Je vais vous montrer comment forçer le type d'un pointeur à partir d'un exemple:
char *p;
p=(char*)malloc(5);
---> on forçe le type de pointeur retourné par malloc à être char.
celui là je l'ai connue mais j'ai vous demandé de m'aider à comprendre à partir d'un exercice comme un exemple qui s'intèresse sur les opérations et le forçage de type sur le pointeur et si vous ne dérrangez pas aidez moi à mieux comprendre la notion du pointeur SVP essayez encore pour m'aidez
je compte sur vous et sur vous competances excellentes car j'en ai besoin primo pour mon savoir et pour mon devoir surveillé pour que je sais répondre aux questions comme vous l'aviez dis et je parle du côté algorithmique ou bien du langage C et MERCI BEAUCOUP.

4 réponses

mamiemando Messages postés 33591 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 mars 2025 7 834
20 mars 2009 à 00:37
Bon déjà ce n'est pas la peine de mettre un titre en majuscule, ça pique les yeux.

Tu sembles parler d'un autre fil de discussion mais je ne vois pas duquel tu parles. Et si tu as effectivement déjà ouvert un fil de discussion pourquoi ne pas continuer à parler dedans ?

Ensuite :
p=(char*)malloc(5); 

ne veut rien dire, car là tu alloues une place de 5 octets en mémoire alors qu'un char occupe en mémoire sizeof(char) soit 1 octet. Si tu veux allouer un tableau de 5 caractères il serait plus propre d'écrire :
p=(char*)malloc(5*sizeof(char)); 


Maintenant il faut que tu comprennes le principe de pointeur.

Qu'est ce qu'un pointeur ? juste une adresse !

Un pointeur c'est juste une adresse. Vois ça comme un entier. Peu importe de quoi il s'agit c'est toujours une adresse. Ainsi sur une architecture 32 bits (ou les adresses sont stockées sur 32 bits), peut importe que tu parles d'un void *, d'un char * ou d'un pouet *, ça fait 4 octets (4 * 8 = 32 bits).

La valeur que stocke un pointeur est interprétée comme une adresse grâce à l'opérateur *. L'opérateur & permet de récupérer l'adresse d'une variable.

Par exemple quand tu peux écrire :
char c = 'a';
char *pc = &c;

La variable pc fait 32 bits et stocke l'adresse mémoire de la variable c. Comme la variable pc est initialisée avec l'adresse de quelque chose qui est encore en mémoire et de type char, ça à du sens d'interpréter ce qui est à l'adresse *pc et de considérer ce qui s'y trouve comme un char (en l'occurrence le caractère 'a').

On pourrait donc se contenter de manipuler uniquement des adresses génériques (notées void *). Alors quel intérêt de typer un pointeur ? Simplement interpréter plus facilement ce qui se trouve à cette adresse. Si je manipule un pointeur pc de type char *, alors en écrivant *pc je suis sensé espérer un char.

Notion de scope

Petit rappel : une variable est désallouée en C lorsqu'on atteint l'accolade fermante de son scope (horizon).
{ // début du scope de a
  int a;
  { // début du scope de b
    int b;
    //...
  } // fin du scope de b
} // fin du scope de a

Un scope inclue également les paires d'accolades définies par une fonction ou un bloc d'instruction, par exemple un if(...){ ... }, un for(...){....}. Bref toute paire d'accolade est un scope, hormis les déclarations de types (struct ....{...}, enum ...{...}, class...{...}).

Qu'est ce qu'une erreur de segmentation ?

Si tu évalues *pc et que l'adresse pc n'a pas été initialisée (par exemple par un malloc ou l'adresse d'un objet qui existe déjà en mémoire et qui n'a pas été désalloué entretemps), alors tu auras une magnifique erreur de segmentation. Exemple :
char *pc;
{
  char c = 'a';
  printf("%c\n",a);
  pc = *a;
  printf("%c\n",*pc);
} // la variable c est désallouée
//...
//...
printf("%c\n",*pc); // n'a plus de sens (sauf si tu as de la chance)

Autre exemple :
char *pc; // pc n'est pas intialisé
// pc contient une valeur aléatoire qui correspond
// très probablement à une adresse invalide
printf("%c\n",*pc); // erreur de segmentation


Que fait un malloc ?

Un malloc s'occupe d'allouer une plage mémoire de taille donnée et retourne l'adresse de cette plage. C'est donc une bonne manière d'initialiser un pointeur. Exemple :
// alloue une plage mémoire qui fait 10*sizeof(int)
int *p = (int *)malloc(10*sizeof(int)); 

Libre à toi de caster cette adresse en ce que tu veux, on s'en fout c'est juste un espace mémoire. Si la variable p sera désallouée à la fin de son scope en tant que variable locale, ce n'est pas le cas de cette plage qui ne correspond pas à une variable locale. Ainsi, la zone mémoire située à cette adresse devra être libérée quand elle ne sera plus utilisée avec un free :
{
  int *p = (int *)malloc(10*sizeof(int));
  // ...
  free(p); // <-- désalloue ce qui est à l'adresse p
} // désalloue p en tant que variable locale de ce scope

Bien entendu, rien ne t'oblige à désallouer p dans le même scope, c'est même souvent rarement le cas. En général on a souvent une fonction qui alloue un objet avec des malloc, et une fonction qui le détruit.
#include <stdlib.h>

struct pouet{
  char *s;
};

struct pouet create(){
  pouet plop;
  plop.s = (char *)malloc(10*sizeof(char));
  return plop;
}

void destroy(struct pouet *pplop){
  free((*pplop).s); // ou free(p->s);
}

int main(){
  struct pouet plop = create();
  // ... j'utilise plop
  destroy(&plop); // sans cette instruction, plop.s ne serait jamais désallouée !
  return 0;
}

Quoi qu'il en soit, qui dit malloc dit free.

Les "tableaux"

Typer des pointeurs permet de manipuler des "tableaux". En soi, il n'y a pas vraiment de tableau en C. C'est plus un raccourci syntaxique ou une vue de l'esprit. Si tu écris :
char buffer[100];

c'est comme si tu déclarais 100 variables de types char à la suite. Le premier caractère se trouve à l'adresse buffer. Ainsi tu dois voir la variable buffer comme un char *. Cependant à la fin du scope de buffer, les 100 caractères consécutifs placés à l'adresse buffer sont désalloués.

Ces 100 caractères sont adjacents en mémoire (et placés tous les sizeof(char) en partant de l'adresse du premier caractère, buffer). Ainsi, écrire :
buffer[69]

... est équivalent à écrire :
*(buffer + 69)

(c'est-à-dire l'adresse de buffer décalées de 69*sizeof(char) puisque buffer est un char *. Ainsi tu vois l'autre intérêt de typer un pointeur : l'opérateur + permet de se décaler du bon nombre de bit. Si je manipulais un int *, l'adresse serait incrémentée de 69*sizeof(int). Évidemment, si tu cherches à accéder à buffer[200], tu atterriras bien après le 100e caractère... et tu auras probablement une belle erreur de segmentation.

Ainsi, écrire une chaîne revient à écrire :
void ecrire(char *s){
  unsigned i;
  for(i=0;s[i]!='\0';++i){
    // lire le caractère placé i*sizeof(char) après &s[0] (== s)
    printf("%c",s[i]); 
  }
}

ou encore :
void ecrire(char *s){
  //++s décale s de sizeof(char) à chaque itération
  for(;*s!='\0';++s){ // s se décale à chaque itération
    printf("%c",*s); 
  }
}

En espérant que c'est plus clair pour toi...

Arbre de dérivation

Dans les programmes un peu évolué, il est fréquent d'avoir des structures qui pointent vers des structures qui elles mêmes pointent vers des structures. Mais le principe reste identique.

On a déjà vu que (*p).champ s'écrivait aussi p->champ. Voici un exemple ou la notation avec des flèches devient plus parlante :
#include <stdio.h>

struct plop1{
  char mon_char;
};

struct plop2{
  struct plop1 pplop1;
};

struct plop3{
  struct plop2 pplop2;
};

int main(){
  struct plop1 x1;
  struct plop2 x2;
  struct plop3 x3;
  x1.mon_char = 'a';
  x2.pplop1 = &x1;
  x3.pplop2 = &x2;
  printf("%c\n",x3->pplop2->pplop1->mon_char); // écrit 'a'
  return 0;
}

Bonne chance
1
Le fil de discussion était le suivant:
http://www.commentcamarche.net/forum/affich 11522388 le forcage de type sur le pointeur
mais elle s'était en fait greffée sur un fil en cours.
Bonne nuit.
0
Bonjour
Tout d'abord j'ai pas fais exprés de mettre le titre de mon message en majuscule c'est par faute d'inattention en tous cas je m'excuse et vous m'avez dis que tu sembles parler avec d'autre fil de discussion j'ai pas continu à parler dedans car j'ai vous envoyé la question depuis deux ou bien trois jours mais vous m'avez pas répondu je m'excuse de nouveau.


Ensuite
J'ai pas compris qu'est ce que c'est un scope et je sais que struct c'est pour déclarer un enregistrement parlant algorithmiquement mais j'ai pas compris que veut dire par pouet et pouet plop et j'ai pas compris cet exemple. Et je sais que buffer c'est une procédure prédéfinie mais je sais pas sa signification càd à quoi ça sert. les exemples que vous m'avez donné ne sont pas tros clair car il ya beaucoup de chose qu'on a pas encore vue dans notre cours .Enfin SVP donnez moi un exercice sur le forçage et les opérations sur le pointeur avec l'enoncé et la correction un simple exercice pas tros évolué car comme j'ai déja dis on a pas beaucoup avancé dans le cours et je m'excuse car j'ai beaucoup vous dérangé et MERCI BEAUCOUP.
0
mamiemando Messages postés 33591 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 mars 2025 7 834
24 mars 2009 à 01:52
J'ai pas compris qu'est ce que c'est un scope et je sais que struct c'est pour déclarer un enregistrement parlant algorithmiquement mais j'ai pas compris que veut dire par pouet et pouet plop et j'ai pas compris cet exemple.


Dans l'exemple "struct pouet" désigne une structure contenant le champ s de type char*. J. Il faut juste que le nom corresponde avec ce que la structure représente. Là j'ai mis un nom au pif, mais j'aurais pu l'appeler "struct tapir" ou n'importe quel autre nom...

Et je sais que buffer c'est une procédure prédéfinie mais je sais pas sa signification càd à quoi ça sert. les exemples que vous m'avez donné ne sont pas tros clair car il ya beaucoup de chose qu'on a pas encore vue dans notre cours .

Non buffer n'est pas une procédure. Soit tu as mal lu ce que j'ai écris, soit il faut que tu reprennes les bases du C. Dans mon exemple buffer est une variable de type char * (donc une adresse). Et rien d'autre. En général une variable appelée buffer (tampon) en français est un espace mémoire qui sert temporairement à stocker de l'information.

Par rapport à ton cours je ne peux pas te dire. La seule chose que tu dois comprendre c'est qu'un pointeur est un variable dont le type se finit par une étoile. Une adresse peu être vue comme une valeur numérique (elle fait 32 bits sur une architecture 32 bits et 64 bits sur une architecture 64 bits quel que soit l'objet qui se trouve à cette adresse). Si l'on tente d'accéder à une adresse non initialisée ou désallouée, on provoque une erreur de segmentation.

Enfin SVP donnez moi un exercice sur le forçage et les opérations sur le pointeur ...

On ne parle pas de "forçage" mais plutôt de cast. C'est typiquement ce qu'on fait lors d'un malloc. Malloc retourne une adresse générique (void *), mais comme je t'ai expliqué, typer un pointeur est bien pratique. On force donc le type de ce pointeur avec un cast.

Exercice : lire une chaîne de caractère dans un buffer. Allouer une chaîne s de taille minimale pouvant stocker la chaîne saisie. Libérer le buffer. Ecrire le contenu de s. Libérer s.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{ // <-- début scope de la fonction main()
    char *s; // variable

    { // <-- début d'un scope (que je vais appeler B, comme bloc)

        char buffer[255]; // variable locale du scope B
        int n;
        scanf("%s",buffer);

        n = strlen(buffer);

        // la chaine est de longueur n, +1 caractère pour stocker '\0'
        s = (char *) malloc(sizeof(char)*(n+1)); // <-- cast
        strcpy(s,buffer);

    } // <-- fin du scope B : ses variables locales (buffer, n) sont désallouées

    printf("s = %s\n",s);
    free(s); // <--  libère la mémoire à l'adresse s (allouée par malloc)
    return 0;
} // <-- fin du scope A, s est libérée (mais pas ce qui s'y trouve, d'où le free)

Bonne chance
0
Bonjour
J'ai pas compris qu'est ce qu'un sope , un pif et struct tapir .puis est ce que ce qu'on fait lors d'un malloc est dit cast bon je m'excuse car ces mots sont nouveaux pour moi et je les ai connue pas . Enfin on a pas encore étudié les fonctions et les procédures prédéfinies dans C car c'est mon première année en faculté mais en mon Bac on a vue les différentes fonctions et procédures prédéfinies algorithmiquement et ces équivalents en Pascal c'est tous c'est pour cela je vous demande de m'aider à les comprendre et les apprendre SVP c'est ça ne te dérrange pas .et Mercie beaucoup pour l'explication.
0
mamiemando Messages postés 33591 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 mars 2025 7 834
25 mars 2009 à 01:33
Je pense que tu devrais commencer par lire un cours de langage C, ce sera plus simple pour nous deux.
https://openclassrooms.com/fr/courses/19980-apprenez-a-programmer-en-c

Quand tu auras bien compris le cours, ce que j'ai écrit devrait devenir subitement beaucoup plus clair.

Il faut que tu comprennes que le concept d'allocation mémoire est spécifique au C et n'a pas d'équivalent en pascal. Ainsi, même si la syntaxe ressemble, tu ne peux passer directement du pascal au C, et c'est pourquoi tu devrais commencer par appréhender ces notions à l'aide d'un cours.

Bonne chance
0