Probleme avec malloc ou pointeur ???
Bonjour, je lutte depuis une heure sur 3 lignes de code qui se compilent mais produisent une erreur lors de l'execution :
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
Y a t'il une absurdite evidente que je ne vois pas ?
Le tout est utilise dans une fonction d'une autre classe. L'erreur qui fait planter le programme est au niveau de *spt=s;
Voila voila...
Merci pour vos efforts.
Clement
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
Y a t'il une absurdite evidente que je ne vois pas ?
Le tout est utilise dans une fonction d'une autre classe. L'erreur qui fait planter le programme est au niveau de *spt=s;
Voila voila...
Merci pour vos efforts.
Clement
A voir également:
- Probleme avec malloc ou pointeur ???
- Pointeur souris - Guide
- Curseur Windows 10 : comment bien voir la souris à l'écran - Guide
- Le pointeur de mon pc portable ne marche plus - Guide
- Un problème d'initialisation avec malloc en C ✓ - Forum C
- Pointeur souris avec rond de chargement qui clignote sans arrêts ✓ - Forum Windows
6 réponses
Alors il manque un peu de code mais en supposant que ce soit un truc du genre :
... ça, ça ne plante pas. Bon ceci dit c'est vraiment une manière bizarre de faire. Vu que tu parles de classe j'en déduis que tu es en C++ il serait donc plus logique d'utiliser new directement (pour désallouer utilise delete) :
Ensuite il faut voir si tu n'as pas réimplémenter l'opérateur =. A priori C++ en définit un par défaut qui recopie tous les champs d'une classe (ou structure) source vers une classe (ou structure) de même type destination. De plus, toujours si tu es en C++, itu peux la plupart du temps te passer des pointeurs et directement utiliser des références. En jouant sur la notion d'horizon (un objet est désalloué quand son horizon prend fin), tu peux gérer la mémoire très simplement. Un horizon (scope) est simplement défini par la paire d'accolade qui englobe "au plus près" la déclaration de ta variable. En dehors de son horizon, une variable perd son sens.
Exemple : ici x reste valable pendant toute la durée du for, z n'a de sens que durant l'itération courante du for, y a un sens durant toute la durée du main
En gros ce que je veux dire c'est que dans ton cas tu n'as peut être même pas besoin de passer par un new, et simplement faire appel au constructeur. En fait si ton objet pointé par le Stone * n'est utilisé que dans l'horizon de ce pointeur, tu peux te passer de ce pointeur et directement faire appel au constructeur :
Bonne chance
#include <cstdlib>
struct Stone{
unsigned x0;
unsigned y0;
unsigned c0;
Stone(unsigned x,unsigned y,unsigned c):
x0(x),y0(y),c0(c)
{}
};
int main(){
unsigned x=3,y=4,c=6;
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
return 0;
}
... ça, ça ne plante pas. Bon ceci dit c'est vraiment une manière bizarre de faire. Vu que tu parles de classe j'en déduis que tu es en C++ il serait donc plus logique d'utiliser new directement (pour désallouer utilise delete) :
struct Stone{
unsigned x0;
unsigned y0;
unsigned c0;
Stone(unsigned x,unsigned y,unsigned c):
x0(x),y0(y),c0(c)
{}
};
int main(){
unsigned x=3,y=4,c=6;
Stone *spt=new Stone(x,y,c);
//...
delete spt;
return 0;
}
Ensuite il faut voir si tu n'as pas réimplémenter l'opérateur =. A priori C++ en définit un par défaut qui recopie tous les champs d'une classe (ou structure) source vers une classe (ou structure) de même type destination. De plus, toujours si tu es en C++, itu peux la plupart du temps te passer des pointeurs et directement utiliser des références. En jouant sur la notion d'horizon (un objet est désalloué quand son horizon prend fin), tu peux gérer la mémoire très simplement. Un horizon (scope) est simplement défini par la paire d'accolade qui englobe "au plus près" la déclaration de ta variable. En dehors de son horizon, une variable perd son sens.
Exemple : ici x reste valable pendant toute la durée du for, z n'a de sens que durant l'itération courante du for, y a un sens durant toute la durée du main
#include <iostream>
int main(){ // debut o
unsigned y=6;
for(unsigned x=0;x<y;x++){ // debut horizon z
unsigned z = 2*x;
std;;cout << z << std::endl;
} // fin horizon z
// x,z n'ont plus de sens et ont été désallouées
std::cout << y << std::endl;
return 0;
}
En gros ce que je veux dire c'est que dans ton cas tu n'as peut être même pas besoin de passer par un new, et simplement faire appel au constructeur. En fait si ton objet pointé par le Stone * n'est utilisé que dans l'horizon de ce pointeur, tu peux te passer de ce pointeur et directement faire appel au constructeur :
struct Stone{
unsigned x0;
unsigned y0;
unsigned c0;
Stone(unsigned x,unsigned y,unsigned c):
x0(x),y0(y),c0(c)
{}
};
int main(){
unsigned x=3,y=4,c=6;
{
Stone s(x,y,c);
// s peut être utilisé
// ....
} // s est désalloué et ne peut plus être utilisé
return 0;
}
Bonne chance
Wouaw, merci pour la grande reponse. Dans le feu de l'action et sous le coup de l'enervement, je n'ai pas ete tres genereux sur les details en effet.
"new" ne resoudrait pas mon probleme je pense mais je suis en effet en C++.
class Board
{
void addMove(int x,int y, string c);
Stone *board[SIZE][SIZE];
};
void Board::addMove(int x,int y, string c)
{
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
board[x][y]=spt;
}
int main()
{
Board b=Board();
b.addMove(1,2,"B");
b.addMove(2,1,"B");
return 0;
}
L'idee est de stocker l'adresse de chaque nouvelle Stone ajoutee. Ecrit comme ca ca parait stupide mais j'en ai vraiment besoin pour autre chose (et je ne peux pas creer un tableau avec des adresses predefinies).
Ceci etant dit, l'erreur est toujours au niveau de *spt=s;
Et meme en mettant juste :
int main()
{
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
}
ca ne marche toujours pas (et ca plante toujours au meme endroit).
Merci pour votre patience
"new" ne resoudrait pas mon probleme je pense mais je suis en effet en C++.
class Board
{
void addMove(int x,int y, string c);
Stone *board[SIZE][SIZE];
};
void Board::addMove(int x,int y, string c)
{
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
board[x][y]=spt;
}
int main()
{
Board b=Board();
b.addMove(1,2,"B");
b.addMove(2,1,"B");
return 0;
}
L'idee est de stocker l'adresse de chaque nouvelle Stone ajoutee. Ecrit comme ca ca parait stupide mais j'en ai vraiment besoin pour autre chose (et je ne peux pas creer un tableau avec des adresses predefinies).
Ceci etant dit, l'erreur est toujours au niveau de *spt=s;
Et meme en mettant juste :
int main()
{
void *stonemem=malloc(sizeof(Stone));
Stone s=Stone(x,y,c);
Stone *spt=(Stone*)stonemem;
*spt=s;
}
ca ne marche toujours pas (et ca plante toujours au meme endroit).
Merci pour votre patience
Rappel sur les pointeurs
J'insiste sur le fait qu'un pointeur est une adresse donc une valeur que tu peux voir comme une simple valeur hexa, et qui fait donc toujours la même taille en mémoire quelque soit ce qui se trouve à cette adresse. Quand tu fais un malloc ou un new tu ne fais que récupérer l'adresse d'une zone que tu viens de réserver. En particulier quand tu fais un new ou un malloc, le pointeur (la variable qui stocke l'adresse) disparaît à la fin du scope en tant que variable locale du scope, mais ce que tu as alloué à cet adresse non. C'est notamment pour ça que tu es sensé faire des free et des delete.
En effet pour chaque new tu es sensé faire un delete (de même que pour chaque malloc tu es sensé faire un free). En général l'allocation se trouve au début d'un scope et la libération à la fin d'un scope :
En C++ grâce au système des constructeurs et des références, les pointeurs ne sont vraiment utiles que dans un cas : faire survivre un objet en dehors du scope dans lequel tu le crées (par exemple dans le constructeur d'une classe), en vue de le détruire beaucoup plus tard (par exemple dans le destructeur de cette classe). Exemple :
Pourquoi ça ne marche pas
En fait si tu as compris ce que je viens de baragouiner tu t'aperçois que ton code ne tient pas debout. En effet tu alloues une zone mémoire pour spt, et ensuite tu lui affectes l'adresse de s qui est alloué le temps de son scope par le constructeur Stone(x,y,c). Si cet objet, pointé par spt, est sensé survivre en dehors du scope, les seules façon de faire sont :
- mettre s dans un scope plus global
- faire un malloc ou un new (seul le pointeur disparaît à la fin du scope, mais l'objet lui reste en vie car ce n'est pas une variable locale).
Ce qu'il faut faire
Dans ton cas ce qu'il faut c'est écrire :
Si l'objet Stone est sensé être accessible en dehors de ce scope (donc en particulier en dehors de ta fonction), comme dit précédemment il faut faire un new (ou un malloc). Puisqu'on est en C++ ce sera donc plutôt un new. Ainsi les 4 lignes :
deviendraient :
Bonne chance
J'insiste sur le fait qu'un pointeur est une adresse donc une valeur que tu peux voir comme une simple valeur hexa, et qui fait donc toujours la même taille en mémoire quelque soit ce qui se trouve à cette adresse. Quand tu fais un malloc ou un new tu ne fais que récupérer l'adresse d'une zone que tu viens de réserver. En particulier quand tu fais un new ou un malloc, le pointeur (la variable qui stocke l'adresse) disparaît à la fin du scope en tant que variable locale du scope, mais ce que tu as alloué à cet adresse non. C'est notamment pour ça que tu es sensé faire des free et des delete.
En effet pour chaque new tu es sensé faire un delete (de même que pour chaque malloc tu es sensé faire un free). En général l'allocation se trouve au début d'un scope et la libération à la fin d'un scope :
{
plop *p =new plop();
//...
delete p;
}
En C++ grâce au système des constructeurs et des références, les pointeurs ne sont vraiment utiles que dans un cas : faire survivre un objet en dehors du scope dans lequel tu le crées (par exemple dans le constructeur d'une classe), en vue de le détruire beaucoup plus tard (par exemple dans le destructeur de cette classe). Exemple :
#include <cstdlib>
class plop_t{
protected:
int *data;
public:
plop_t(unsigned x=0){
// syntaxe C
// data =(data*)malloc(x*sizeof(int));
// syntaxe C++
data = new int[x];
}
~plop_t(){
// syntaxe C
// free(data);
// syntaxe C++
delete data;
}
};
Pourquoi ça ne marche pas
En fait si tu as compris ce que je viens de baragouiner tu t'aperçois que ton code ne tient pas debout. En effet tu alloues une zone mémoire pour spt, et ensuite tu lui affectes l'adresse de s qui est alloué le temps de son scope par le constructeur Stone(x,y,c). Si cet objet, pointé par spt, est sensé survivre en dehors du scope, les seules façon de faire sont :
- mettre s dans un scope plus global
- faire un malloc ou un new (seul le pointeur disparaît à la fin du scope, mais l'objet lui reste en vie car ce n'est pas une variable locale).
Ce qu'il faut faire
Dans ton cas ce qu'il faut c'est écrire :
Stone s=Stone(x,y,c); Stone *spt=&s;
Si l'objet Stone est sensé être accessible en dehors de ce scope (donc en particulier en dehors de ta fonction), comme dit précédemment il faut faire un new (ou un malloc). Puisqu'on est en C++ ce sera donc plutôt un new. Ainsi les 4 lignes :
void *stonemem=malloc(sizeof(Stone)); Stone s=Stone(x,y,c); Stone *spt=(Stone*)stonemem; *spt=s;
deviendraient :
Stone *spt = new Stone(x,y,c); //... delete spt;
Bonne chance
En fait si tu as compris ce que je viens de baragouiner tu t'aperçois que ton
code ne tient pas debout. En effet tu alloues une zone mémoire pour spt, et
ensuite tu lui affectes l'adresse de s qui est alloué le temps de son scope par
le constructeur Stone(x,y,c). Si cet objet, pointé par spt, est sensé survivre
en dehors du scope, les seules façon de faire sont :
- mettre s dans un scope plus global
- faire un malloc ou un new (seul le pointeur disparaît à la fin du scope, mais
l'objet lui reste en vie car ce n'est pas une variable locale).
Je ne touche pas a l'adresse de s justement...L'adresse de s etant toujours la meme quel que soit l'appel de fonction il faut que je trouve autre chose pour avoir l'objet et sa reference, ce que semblait me permettre malloc.
Je viens de tester avec Stone*test=new Stone(x,y,c) et ca ne resoud pas le probleme.
L'adresse contenue en board2[x][y] qui est un attribut de la classe Board est toujours la meme.
Concretement j'ai juste ecrit
malloc resolvait mon probleme en allouant effectivement des adresse differentes a chaque appel de la fonction. Mais je n'arrive juste pas a remplir cette adresse.
Le probleme est il different ? Ai-je mal compris ce que tu avais dit ?
code ne tient pas debout. En effet tu alloues une zone mémoire pour spt, et
ensuite tu lui affectes l'adresse de s qui est alloué le temps de son scope par
le constructeur Stone(x,y,c). Si cet objet, pointé par spt, est sensé survivre
en dehors du scope, les seules façon de faire sont :
- mettre s dans un scope plus global
- faire un malloc ou un new (seul le pointeur disparaît à la fin du scope, mais
l'objet lui reste en vie car ce n'est pas une variable locale).
Je ne touche pas a l'adresse de s justement...L'adresse de s etant toujours la meme quel que soit l'appel de fonction il faut que je trouve autre chose pour avoir l'objet et sa reference, ce que semblait me permettre malloc.
Je viens de tester avec Stone*test=new Stone(x,y,c) et ca ne resoud pas le probleme.
L'adresse contenue en board2[x][y] qui est un attribut de la classe Board est toujours la meme.
Concretement j'ai juste ecrit
Stone *stonemem=new Stone(x,y,c); board2[x][y]=stonemem; delete stonemem;
malloc resolvait mon probleme en allouant effectivement des adresse differentes a chaque appel de la fonction. Mais je n'arrive juste pas a remplir cette adresse.
Le probleme est il different ? Ai-je mal compris ce que tu avais dit ?
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Bon plaçons nous dans ton cas. Apparemment si j'ai bien compris tu crée une sorte de tableau 2D de Stone *. Donc il faut que ce soit le constructeur du tableau board2 qui alloue ces "Stone" (et il les détruira dans son destructeur). Un exemple :
A l'exécution ça donne :
Bonne chance
#include <iostream>
struct stone_t{
unsigned x;
unsigned y;
char c;
stone_t(){}
stone_t(unsigned x0,unsigned y0,char c0):x(x0),y(y0),c(c0){}
};
std::ostream & operator << (std::ostream & out,const stone_t & s){
out << "[x=" << s.x << ",y=" << s.y << ",c=" << s.c << ']';
return out;
}
class board2d_t{
protected:
stone_t ***data;
unsigned size_x;
unsigned size_y;
public:
board2d_t(unsigned size_x0,unsigned size_y0):
size_x(size_x0),size_y(size_y0)
{
data = new stone_t**[size_y];
for(unsigned y=0;y<size_y;++y){
data[y] = new stone_t*[size_x];
for(unsigned x=0;x<size_x;++x){
data[y][x] = new stone_t(x,y,'c');
}
}
}
~board2d_t(){
std::cout << "calling ~board2d_t" << std::endl;
for(unsigned y;y<size_y;++y){
for(unsigned x=0;x<size_x;++x) delete data[y][x];
delete data[y];
}
delete data;
}
inline stone_t *** const get_data() const{
return data;
}
inline unsigned get_size_x() const{
return size_x;
}
inline unsigned get_size_y() const{
return size_y;
}
};
std::ostream & operator << (std::ostream & out,const board2d_t & board2d){
stone_t ***data = board2d.get_data();
unsigned size_x = board2d.get_size_x();
unsigned size_y = board2d.get_size_y();
for(unsigned y=0;y<size_y;++y){
for(unsigned x=0;x<size_x;++x) out << *(data[y][x]) << '\t';
out << std::endl;
}
return out;
}
int main(){
{
board2d_t board2d(5,4);
std::cout << board2d << std::endl;
} // <-- fin du scope de board2d => appel de ~board2d_t
std::cout << "fin" << std::endl;
return 0;
}
A l'exécution ça donne :
(mando@aldur) (~) $ ./a.out [x=0,y=0,c=c] [x=1,y=0,c=c] [x=2,y=0,c=c] [x=3,y=0,c=c] [x=4,y=0,c=c] [x=0,y=1,c=c] [x=1,y=1,c=c] [x=2,y=1,c=c] [x=3,y=1,c=c] [x=4,y=1,c=c] [x=0,y=2,c=c] [x=1,y=2,c=c] [x=2,y=2,c=c] [x=3,y=2,c=c] [x=4,y=2,c=c] [x=0,y=3,c=c] [x=1,y=3,c=c] [x=2,y=3,c=c] [x=3,y=3,c=c] [x=4,y=3,c=c] calling ~board2d_t fin
Bonne chance