Les pointeurs, aide SVP

cs_jb60 Messages postés 55 Date d'inscription mardi 16 septembre 2003 Statut Membre Dernière intervention 4 août 2008 - 21 oct. 2004 à 01:41
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 - 22 oct. 2004 à 18:53
Bonjour,

J'ai fait une source avec plusieurs fichier *.cpp et plusieurs fichiers *.h
Dans un fichier main.cpp, j'ai créé un pointeur BYTE *LesOctets;
Je n'ai donc à ce moment pas encore alloué d'espace pour la mémoire...
Je souhaite le faire par le biais d'une fonction (déclarée dans un autre fichier) qui a pour prototype
BOOL LectureFichier(char * NomDeFichier, BYTE *Buffer);
Dans laquelle je vais rentrer dans BYTE *Buffer le nom LesOctets.
C'est à dire qu'en utilisant cette fonction, je vais écrire (dans le fichier main.cpp ou est déclaré le pointeur BYTE *LesOctets):
LectureFichier(szFileName,LesOctets);

Durant cette fonction, je souhaite allouer de la mémoire pour le pointeur LesOctets, en faisant:
Buffer = new BYTE[tailleFichier] //TailleFichier étant calculée juste avant.
Dans la fonction, l'allocation de mémoire fonctionne parfaitement, mais lorsque je souhaite utiliser le pointeurs LesOctets dans le fichier main.cpp, le pointeur reste NULL. Je n'arrive donc pas à récupérer les octets que je viens de rentrer dans le pointeur LesOctets dans le fichier main.cpp.

Or, ceci doit être possible, comme on peut le trouver dans plusieurs fonctions standard du c++, telles que sprintf(szBuffer,"texte formatté",...);

Je ne sais pas comment faire, si quelqu'un peut m'aider, ça serait bien sympathique.
Je pourrais peut être donner mon code source pour exemple:

//fichier main.cpp
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HANDLE hFile;
static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH];
static BYTE *LesOctetsDuFichier;
TCHAR TestBuffer[5000];
static DWORD iFileSize;
int wmId, wmEvent;
RECT rect;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
//case WM_INITDIALOG:
//PopFileInitialize(hWnd);
//break;

case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Analyse les sélections de menu :
switch (wmId)
{
case IDM_FILE_OPEN:
if (PopFileOpenDlg(NULL,szFileName,szTitleName))
{
if (!LectureDuFichier(szFileName, LesOctetsDuFichier, &iFileSize))
MessageBox(hWnd,TEXT("Erreur lors de la lecture du fichier"),TEXT("Attention"),MB_OK);
else
{
//sprintf(TestBuffer,TEXT("Taille du fichier lue dans WinProc = %d"),iFileSize);
//MessageBox(NULL,TestBuffer,TEXT("Info"),MB_OK);
InvalidateRect(hWnd,NULL,TRUE);
}
}
break;

case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
if (LesOctetsDuFichier!=NULL) //si on a rentré des données dans les octets à traiter
{
GetClientRect(hWnd,&rect);
MessageBox(hWnd,TEXT("Nous sommes dans le cas ou des données sont présentes dans le buffer des octets du fichier"),TEXT("Info"),MB_OK);
DrawText(hdc,(LPCTSTR) LesOctetsDuFichier,-1,&rect,DT_LEFT);
}
// TODO : ajoutez ici le code de dessin...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

//fichier secondaire.cpp
BOOL LectureDuFichier(PTSTR pFileName, BYTE *Buffer, DWORD *TailleDuFichier)
{
DWORD nbreOfBytesRead;
BYTE *Buffer2;
TCHAR TestBuffer[500];

HANDLE hFile=CreateFile(pFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile==INVALID_HANDLE_VALUE)
{
MessageBox(NULL,TEXT("Erreur de lecture du fichier spécifié, veuillez recommencer..."),TEXT("Erreur"),MB_OK);
return FALSE; //on sort de la fonction, car une erreur s'est produite
}

(*(TailleDuFichier))=GetFileSize(hFile,NULL);

//sprintf(TestBuffer,TEXT("Taille du fichier = %d"),(*(TailleDuFichier)));
//MessageBox(NULL,TestBuffer,TEXT("Info"),MB_OK);

Buffer2 = new BYTE[(*(TailleDuFichier))+1];

ReadFile(hFile,Buffer2,(*(TailleDuFichier)),&nbreOfBytesRead,NULL);

if (nbreOfBytesRead<(*(TailleDuFichier)))
{
CloseHandle(hFile);
delete Buffer2;
return FALSE;
}

Buffer2[(*(TailleDuFichier))]='\0'; //on met le caractère nul à la fin du buffer

if (Buffer!=NULL) {MessageBox(NULL,"Erreur de buffer non nul","info",MB_OK); delete Buffer;}

sprintf(TestBuffer,TEXT("Adresse du buffer avant new = %X"),Buffer);
MessageBox(NULL,TestBuffer,TEXT("Info"),MB_OK);

Buffer = new BYTE[(*(TailleDuFichier))+1]; //on alloue de la mémoire pour le tableau de bytes utilisé dans WinProc

sprintf(TestBuffer,TEXT("Adresse du buffer après new = %X"),Buffer);
MessageBox(NULL,TestBuffer,TEXT("Info"),MB_OK);

for (unsigned int i=0;i<(*(TailleDuFichier));i++)
*(Buffer+i)=*(Buffer2+i); //On copie les données dans le buffer que l'on pourra utiliser dans WinProc

CloseHandle(hFile);
delete Buffer2;
return TRUE;
}

En esperant avoir des réponses rapidement, merci.
:-)

JB

16 réponses

cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
21 oct. 2004 à 03:03
Salut,
Pour modifier une variable depuis une fonction, il faut passer la variable par adresse.
Meme logique pour les pointeurs: pour modifier un pointeur depuis une fonction, il faut passer le pointeur par adresse, c'est a dire un pointeur de pointeur.

ta func doit etre prototypée comme ca:
BOOL LectureFichier(char * NomDeFichier, BYTE ** Buffer);

et il faut passer &LesOctets en param.

et dans la fonction tu modifies Buffer:
*Buffer = ... ;
0
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
21 oct. 2004 à 08:51
beaucoup plus simple en c++, passage par reference

BOOL LectureFichier(char * NomDeFichier, BYTE * (&Buffer) );
0
magic_Nono Messages postés 1878 Date d'inscription jeudi 16 octobre 2003 Statut Membre Dernière intervention 16 mars 2011
21 oct. 2004 à 09:22
+ simple certes mais source d'erreur

personnellement je préconnise:
référence constante pour donnée non modifiable

et
adresse pour donnée modifiable

sinon, initialise bien ton ptr à NULL au début, ça pourrait éviter des erreurs et des fuites mem

++

Magic Nono: l'informagicien! 8-)
0
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
21 oct. 2004 à 09:39
arrete, en c++ on utilise les references et on oubli les pointeurs qui sont eux sources d'erreurs et de gros plantage

d'ailleur le passage par reference est plus puissant que le passage par pointeur en c, ca créé un veritable alias de n'importe quel type

tu sais bien que le but des references c'est de ne plus avoir à utiliser de pointeurs ?
0

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

Posez votre question
magic_Nono Messages postés 1878 Date d'inscription jeudi 16 octobre 2003 Statut Membre Dernière intervention 16 mars 2011
21 oct. 2004 à 10:50
ui djl

mais
peux tu plus développer stp
("plus puissant "& "veritable alias ")
que je sache, au final, c'est tjs une adresse qui est transmise...

pkoi po les utiliser, ç change juste l'utilisation:
-> en . et *truc=... en truc=...

je trouve que ça le fait ressortir,
mais C vrai que C la vieille école du C...
++
Magic Nono: l'informagicien! 8-)

PS: certes complexes à maitriser au début, mais on fait quasi tt avec les ptr :shy)
0
cs_jb60 Messages postés 55 Date d'inscription mardi 16 septembre 2003 Statut Membre Dernière intervention 4 août 2008
21 oct. 2004 à 19:35
OK les gars,

Je vous remercie bien, je vais essayer vos trucs, et je choisirai par la suite entre pointeurs et references, je verrais le plus simple...

++
et encore merci (si ca ne marche pas, je referais un message, lol)

JB
0
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
21 oct. 2004 à 20:02
jb60 > ya pas photo, utiliser les references c'est profiter d'un fabuleux outil offert par le c++

magic_Nono > alias 'pour' n'importe quel type je voulais dire, par exemple pour les tableaux multidim

entre

void f(int *n)
{
*n = 5;
}

...

f(&n);

et

void f(int &n)
{
n = 5;
}

...

f(n);

rien que sur cette exemple simplissime on voit tout de suite que le passage par pointeur sera source d'erreur alors qu'avec reference c'est completement transparent

void f( truc **t )
{
*t = new truc[...];

for( ... )
{
(*t)[i] = ...
}
}

void f( truc * (&t) )
{
t = new truc[...];

for(...)
{
t[i] = ... ;
}
}

c'est la peine de continuer ?
0
cs_jb60 Messages postés 55 Date d'inscription mardi 16 septembre 2003 Statut Membre Dernière intervention 4 août 2008
21 oct. 2004 à 20:45
J'ai une autre question...
Voilà la source que j'ai entrée (désolé djl pour ne pas avoir utilisé les références tout de suite, lol):

BOOL LectureDuFichier(PTSTR pFileName, BYTE **Buffer, DWORD *TailleDuFichier)
{
DWORD nbreOfBytesRead;
//TCHAR TestBuffer[500];

HANDLE hFile=CreateFile(pFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile==INVALID_HANDLE_VALUE)
{
MessageBox(NULL,TEXT("Erreur de lecture du fichier spécifié, veuillez recommencer..."),TEXT("Erreur"),MB_OK);
return FALSE; //on sort de la fonction, car une erreur s'est produite lors de l'accès au fichier
}

(*(TailleDuFichier))=GetFileSize(hFile,NULL);

if (*Buffer!=NULL) {MessageBox(NULL,"Erreur de buffer non nul","info",MB_OK); delete Buffer;}

*Buffer = new BYTE[(*(TailleDuFichier))+1]; //on alloue de la mémoire pour le tableau de bytes utilisé dans WinProc

ReadFile(hFile,*Buffer,(*(TailleDuFichier)),&nbreOfBytesRead,NULL);

//sprintf(TestBuffer,TEXT("Nous sommes juste après ReadFile"));
//MessageBox(NULL,TestBuffer,TEXT("Info"),MB_OK);

if (nbreOfBytesRead<(*(TailleDuFichier)) )
{
MessageBox(NULL,TEXT("Attention, le buffer ne devrait pas etre delete"),TEXT("Erreur"),MB_OK);
CloseHandle(hFile);
delete *Buffer;
return FALSE; //on sort de la fonction
}

(*Buffer)[*(TailleDuFichier)]='\0'; //on met le caractère nul à la fin du buffer

CloseHandle(hFile);
return TRUE;
}

et en fait, lorsque j'utilise une première fois la fonction, c'est bon, ca marche, mais ensuite si je réutilise ma fonction, alors une adresse est présente dans LesOctets (représenté par Buffer dans la fonction). Donc je delete cette adresse, pour réallouer une zone mémoire avec assez d'espace pour contenir les prochaines données. Or, le programme plante lorsque je suis dans la boucle
if (*Buffer!=NULL) {MessageBox(NULL,"Erreur de buffer non nul","info",MB_OK); delete Buffer;}
comme si je ne pouvais pas delete le pointeur, alors que je l'ai initialisé précédemment avec l'opérateur new...

Si quelqu'un comprends cette erreur, je suis preneur de la réponse.

Merci.

++

JB
0
cs_jb60 Messages postés 55 Date d'inscription mardi 16 septembre 2003 Statut Membre Dernière intervention 4 août 2008
21 oct. 2004 à 20:54
Au fait djl,

Est-ce qu'avec un passage par référence on peut utiliser l'opérateur new et delete, comme avec des pointeurs?
Ou y'a t'il quelque chose de spécial à faire?

JB
0
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
21 oct. 2004 à 21:02
oui, si tu passes un pointeur par reference

en gros, fais comme si c'etais un passage par valeur, sauf qu'au lieu de travailler sur un copie locale de la variable passer en argument, tu travailles directement dessus et tu peux donc la modifier
0
cs_jb60 Messages postés 55 Date d'inscription mardi 16 septembre 2003 Statut Membre Dernière intervention 4 août 2008
21 oct. 2004 à 21:38
OK, merci

JB
0
plus_plus_fab Messages postés 232 Date d'inscription vendredi 9 janvier 2004 Statut Membre Dernière intervention 8 janvier 2005
21 oct. 2004 à 22:04
djl > ton exemple avec f(n), f(&n) est justement l'illustration du fait que les références ne se sont pas imposés (comme elles le méritent).
Si tu ne connais pas la déclaration de f, et que tu fais f(n), tu ne peux pas savoir si n peut éventuellement etre modifié. avec un appel f(&n), tu sais que si.

Sinon, la commodité d'écriture, je m'en moque un peu perso, mais c'est manifeste.

L'interet des références qui n'a pas été souligné, c'est que ça pointe constament vers qqchose. C'est comme un pointeur type *const ptr; auquel on applique l'indirection à chaque usage. C'est une information en plus pour le compilateur, qui lésine rarement à optimiser.

Ca évite aussi les erreurs, f(&n) avec un n non alloué, c'est le crash ...
f(n) forcément non (une référence est obligatoirement affecté à la déclaration)
0
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
21 oct. 2004 à 22:11
"Si tu ne connais pas la déclaration de f, et que tu fais f(n), tu ne peux pas savoir si n peut éventuellement etre modifié. avec un appel f(&n), tu sais que si."

ca se tient, pour une question de lisibilité, mais ca c'est un gros defaut du c++ tout ces mechanismes planqués

sinon comme tu l'as dit, un reference fais toujours references q qqchose et lors de la declaration elle doit etre initialisée

type& r = ...

en gros ca rejoins le faite que ca evite de faire des erreurs contrairement aux pointeurs qui en sont souvent la source
0
magic_Nono Messages postés 1878 Date d'inscription jeudi 16 octobre 2003 Statut Membre Dernière intervention 16 mars 2011
22 oct. 2004 à 14:08
Voici mis en mots ce que je cherchais à dire:

"Si tu ne connais pas la déclaration de f, et que tu fais f(n), tu ne peux pas savoir si n peut éventuellement etre modifié. avec un appel f(&n), tu sais que si."

C à l'usage des fonctions & a la relecture que C + claire avec des ptr: on sait de suite, sans voir la fonction si ses param sont modifiés.

Point final sur ce débat

Après, chacun utilise se qui lui semble le plus judicieux et quand on est sur un prj en commun, on fixe ces détails au départ.

Magicalement.

Magic Nono: l'informagicien! 8-)

PS G promis des prog a certain mais mon PC a fumé (carte mere & carte vidéos mortes... jutilise le portable entretemps..)
Des que C changé (pr mon ani probablement, je posterai tt ça)
Dslé ++
0
magic_Nono Messages postés 1878 Date d'inscription jeudi 16 octobre 2003 Statut Membre Dernière intervention 16 mars 2011
22 oct. 2004 à 14:08
16/11 pr la précision
0
cs_djl Messages postés 3011 Date d'inscription jeudi 26 septembre 2002 Statut Membre Dernière intervention 27 novembre 2004 7
22 oct. 2004 à 18:53
magic_Nono > ...

"Si tu ne connais pas la déclaration de f, et que tu fais f(n), tu ne peux pas savoir si n peut éventuellement etre modifié. avec un appel f(&n), tu sais que si."

oui pour la lisibilité, entierement d'accord et c'est meme un defaut recurrent du c++

mais à l'usage non, absolument pas, si tu utilises une fonction sans savoir ce qu'elle fais, sans connaitre son prototype, t'es deja dans le mur

moi ce que je vois c'est que dans pratiquement tout les langages de haut niveau, les parametre sont in/out de maniere transparente
0
Rejoignez-nous