See site in english Voir le site en francais
Website skin:
home  download  forum  link  contact

Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

Author Topic: [Help C++] Saloperie de char* !!!  (Read 1824 times)

0 Members and 1 Guest are viewing this topic.

Offline laserpithium

  • Legend
  • ******
  • Posts: 1473
  • Karma: 0
02 August 2008, 13:36:41
Comme le titre le suggère, j'ai un problème avec ces saloperies de char *...

Je m'explique:
SuborbMFD est capable de vous poser en automatique sur le pad de la base de votre choix. Dans les versions précédentes de
SuborbMFD, on entrait uniquement le nom de la base. Maintenant, il faut aussi préciser le numéro de pad. Cela se fait sous le
format nom_de_le_base:numero_de_pad
(ex: Brighton Beach:3 pour le pad N°3 de Brighton Beach).
Orbiter me renvoie un char *str
Je souhaite extraire de ce char* le nom de la base et le numéro de pad.

Mon code est le suivant:
char *base = NULL;
char pad[3];
char *ptr;
const char delimiteur = ':';
ptr = strchr(str,delimiteur);
base = (char *)malloc (sizeof (*base) * (ptr - str + 2));
strncpy(base,str,ptr-str);
strncpy(pad,ptr+1,1);
int numPad = max(atoi(pad)-1,0);

Le problème, c'est que ça ne marche pas à tout les coups...
si après la ligne strncpy(base,str,ptr-str);
je fais un sprintf(oapiDebugString(),"%s",base);
j'obtiens parfois le nom de la base ("Brighton Beach" dans mon exemple) et la routine fonctionne, mais parfois j'obtiens le
nom de la base suivi de caractères bidons, et le nom de la base n'est donc évidemment pas reconnu...
Le problème doit être du côté du malloc, mais je vois pas comment ça peut parfois marcher et parfois non...

PS: je précise qu'il ne s'agit bien évidemment qu'un extrait du code, le cas où le délimiteur n'est pas trouvé etc est traité ailleurs.



Message modifié ( 02-08-2008 13:38 )


La sagesse me cours après, mais je suis plus rapide
Si Dieu existe, butons-le !

Offline DanSteph

  • Administrator
  • Legend
  • *****
  • Posts: 15407
  • Karma: 256
  • Hein, quoi !?
    • FsPassengers
Reply #1 - 02 August 2008, 15:15:11
Faudrais poster tout le code avec la fonction Orbiter SVP et entre tag [code ] [/code ] merci.

Je ne vois pas quel fonction tu appelle mais je te conseille d'éviter comme la peste les allocation dynamique (malloc),
c'est un truc à ce mélanger les pinceaux et ce faire des memory leak ou des CTD. Une horreur crois moi.

Par exemple si tu appelle la fonction:

Code: [Select]
int oapiGetNavDescr (NAVHANDLE hNav,char *descr,int maxlen)
qui retourne justement un char tu t'emmerde pas, tu lui passe un char de 255 avec ca t'est sur d'avoir de la place:

Code: [Select]
char BaseDescr[255]={0};
oapiGetNavDescr (hNav,BaseDescr,254); // 254 pour pas avoir de merde avec le null de fin

Pour que je te poste une soluce faudrait que tu poste justement ton code complete aussi pour cette partie. Je vois
pas quel fonction te retourne "NoPad:nom de la base" !?

Mais admettons que ta fonction te renvoie ca, moi je ferais ca:

Code: [Select]
char cStringComplete[255]={0};                      // initialise a zéro la chaine!!!
TaFonctionQuiRenvoieChar(cStringComplete,254); // get la string complete
char *cPtr=strstr(cStringComplete,":");             // recherche la séparation
*cPtr=0;                                            // met un zéro a la place
int iNumeroDeBase=atoi(cStringComplete);            // atoi le début
char cNomDeLaBaseFinale[255]={0}; // initialise a zéro la chaine!!!
strcpy(cNomDeLaBaseFinale,cPtr+1);                  //copie le nom de la base

Tu te retrouve avec le résultat dans "iNumeroDeBase" et "cNomDeLaBaseFinale"

Mais ATTENTION !!! ya aucun controle d'erreur la dedans, si ca merde c'est le CTD, la bonne methode c'est de tout
tester les retours.

Code: [Select]
char cStringComplete[255]={0};                      // initialise a zéro la chaine!!!
if(TaFonctionQuiRenvoieChar(cStringComplete,254)<2)
return ERREUR;
char *cPtr=strstr(cStringComplete,":");             // recherche la séparation
if(!cPtr)
return ERREUR;
*cPtr=0;                                            // met un zéro a la place
int iNumeroDeBase=atoi(cStringComplete);            // atoi le début
char cNomDeLaBaseFinale[255]={0}; // initialise a zéro la chaine!!!
strcpy(cNomDeLaBaseFinale,cPtr+1);                  //copie le nom de la base
if(strlen(cNomDeLaBaseFinale)<2)
   return ERREUR;

Comme t'est en scope local tu perd pas un byte de place et tu te fais pas chier avec des allocs dynamique pourrie.
Après comment tu a besoin du retour c'est à toi de me dire comment tu le veux si ca te pose encore un probleme.

Comme tu vois je suis "root", la ou y a besoin de 60 char dans la doc je lui passe 255, la ou j'ai besoin de 255 je lui passe 1024 et j'initialise toutes mes chaines à zero. pour les retour de fonction je ratisse large aussi <2 au lieu de ==0 pour erreur. (et si le gars c'est planté et retourne - quelque chose?) J'évite comme la peste les alloc dynamique. C'est du bon gros rouge qui tache mais mes progs plantent très peux, je laisse les ciselures aux adeptes des CTD.

ces habitudes te sauverons quelques cheveux.


Dan



Message modifié ( 02-08-2008 15:31 )


Offline laserpithium

  • Legend
  • ******
  • Posts: 1473
  • Karma: 0
Reply #2 - 02 August 2008, 15:28:26
OK Dan, merci pour ton aide.

Voici donc mon code:

Déjà, on récupère le clic sur le bouton du MFD pour entrer le nom de la cible (fonction de l'API)
Code: [Select]
//Récupération des clics utilisateurs
bool SuborbMFD::ConsumeKeyBuffered (DWORD key)
{
bool cbChooseTGT(void *id, char *str, void *data);

switch (key) {
case OAPI_KEY_T:
if(modeAction != -1)
{
if(langueEnglish) oapiOpenInputBox("Select Target :", cbChooseTGT, 0, 20, (void*)this);
else oapiOpenInputBox("Choix de la destination :", cbChooseTGT, 0, 20, (void*)this);
}
return true;
}
}

ensuite, on récupère l'info et on la traite dans la fonction cbChooseTGT:

Code: [Select]
bool SuborbMFD::chooseTGT(char *str)
{
char *base = NULL;
char pad[3];
char *ptr;
const char delimiteur = ':';
ptr = strchr(str,delimiteur);
OBJHANDLE baseChoisie;
if(ptr == NULL)
{
base = (char *)malloc (sizeof (*base) * (strlen(str) + 2));
strcpy(base,str);
}
else
{
base = (char *)malloc (sizeof (*base) * (ptr - str + 2));
strncpy(base,str,ptr-str);
}
sprintf(oapiDebugString(),"%s",base);
baseChoisie = oapiGetBaseByName(body.corps,base);
if(baseChoisie == NULL) return false;
else
{//Alors on choix du pad
int numTotalPad = oapiGetBasePadCount(baseChoisie);
if(numTotalPad == 0) oapiGetBaseEquPos(baseChoisie,&cible.lonCR,&cible.latCR);
else
{
if(ptr == NULL)
{ //Alors choix au hasard parmi les dispos
int status;
bool trouve = false;
int k=0;
while(k<numTotalPad && !trouve)
{
oapiGetBasePadStatus(baseChoisie,k,&status);
if(status==0)
{
trouve = true;
cible.numPad = k;
}
k++;
}
if(!trouve)
{
baseChoisie = NULL;
autoPilotes.approach.modeAuto = false;
return false;
}
}
else
{ //On v�rifie si ce pad est libre, sinon on jette
strncpy(pad,ptr+1,1);
int numPad = max(atoi(pad)-1,0);
if(numPad<0 || numPad>=numTotalPad)
{
baseChoisie = false;
autoPilotes.approach.modeAuto = false;
return false;
}
else
{
int status;
oapiGetBasePadStatus(baseChoisie,numPad,&status);
if(status == 0) cible.numPad = numPad;
else
{
baseChoisie = false;
autoPilotes.approach.modeAuto = false;
return false;
}
}
}
}
}
//Si on est toujours vivant, c'est que c'est bon.
cible.baseCible = baseChoisie;
//extraction des coordonnées de la base
oapiGetBasePadEquPos(cible.baseCible,cible.numPad,&cible.lonCR,&cible.latCR);
cible.latC = cible.latCR*radian;
cible.lonC = cible.lonCR*radian;
SuborbMFD::calcul();
return true;
}

Voilà, le nom de la base étant saisie sous la forme nom_de_la_base:numéro_de_pad (exemple: "Brighton Beach:3").

Merci Dan.



La sagesse me cours après, mais je suis plus rapide
Si Dieu existe, butons-le !

Offline DanSteph

  • Administrator
  • Legend
  • *****
  • Posts: 15407
  • Karma: 256
  • Hein, quoi !?
    • FsPassengers
Reply #3 - 02 August 2008, 15:51:17
Tient! T'a un joli leak la justement avec ton malloc ;)

Le gars peut rentrer juste un nom et pas le no de pad si je comprend bien ?

Perso rentrer des noms dans un mfd ca me fait ch... tu pourrais pas plutot faire un systeme de browsing,
t'a une page "choose target" qui te propose toutes les base de la planetes, tu navigue avec haut/bas
enter tu selectionne tu navigue dans les no de pad, enter tu selectionne.

Mais bon, c'est comme tu veux, je te post la modif dans un moment... ;)
(dès que j'aurais tout pigé ton code)

Dan


Offline DanSteph

  • Administrator
  • Legend
  • *****
  • Posts: 15407
  • Karma: 256
  • Hein, quoi !?
    • FsPassengers
Reply #4 - 02 August 2008, 16:20:34
voila chef, je t'ai mis aussi le cpp en download pour eviter les prob de copie/past:

http://orbiter.dansteph.com/laser.cpp

Sinon ca a cette gueule:

Code: [Select]
bool SuborbMFD::chooseTGT(char *str)
{
char base[255]={0}; // nom de la base
OBJHANDLE baseChoisie=NULL; // !!!TOUJOURS initialiser les handles!!!
int iNumeroDePad=-1; // numero de pad, -1 pas de numéro

// y a eu un merde le gars a rien rentré
// ou autres problemes. on sais jamais
if(str==NULL)
return false;
if(strlen(str)<2)
return false;

// recherche la séparation si y a un numéro de pad
char *cPtr=strstr(str,":");            
// on a un numéro aussi, prend le
// et sépare la string en deux avec un zero.
if(cPtr!=NULL)
{
*cPtr=0;                            // sépare la string en deux
iNumeroDePad=atoi(cPtr+1); // prend le numéro de pad
if(iNumeroDePad<0||iNumeroDePad>50) // assure une premiere validation
iNumeroDePad=-1;
}
//copie le nom de la base
strcpy(base,str);                  
// pas de nom valide ? ca pue le gars a merdé !
if(strlen(base)<3)
return false;

// la on est bon, au moins un nom de base
// et possible aussi un numéro de pad
// sinon iNumeroDePad==-1

sprintf(oapiDebugString(),"base: %s pad: %i",base,iNumeroDePad);
baseChoisie = oapiGetBaseByName(body.corps,base);
if(baseChoisie == NULL)
return false; // pas trouvé, au revoir !
else
{
//Alors on choix du pad
int numTotalPad = oapiGetBasePadCount(baseChoisie);
if(numTotalPad == 0)
{
oapiGetBaseEquPos(baseChoisie,&cible.lonCR,&cible.latCR);
}
else
{
// pas de pad spécifié ?
//Alors choix au hasard parmi les dispos
if(iNumeroDePad<0)
{
int status;
bool trouve = false;
int k=0;
while(k<numTotalPad && !trouve)
{
oapiGetBasePadStatus(baseChoisie,k,&status);
if(status==0)
{
trouve = true;
cible.numPad = k;
}
k++;
}
if(!trouve)
{
baseChoisie = NULL;
autoPilotes.approach.modeAuto = false;
return false;
}
}
else
{ //On verifie si ce pad est libre, sinon on jette
// on est dans le range au moins ?
if(iNumeroDePad>=numTotalPad)
{
baseChoisie = false;
autoPilotes.approach.modeAuto = false;
return false;
}
else
{
int status;
oapiGetBasePadStatus(baseChoisie,iNumeroDePad,&status);
if(status == 0)
cible.numPad = iNumeroDePad;
else
{
baseChoisie = false;
autoPilotes.approach.modeAuto = false;
return false;
}
}
}
}
}
//Si on est toujours vivant, c'est que c'est bon.
cible.baseCible = baseChoisie;
//extraction des coordonnées de la base
oapiGetBasePadEquPos(cible.baseCible,cible.numPad,&cible.lonCR,&cible.latCR);
cible.latC = cible.latCR*radian;
cible.lonC = cible.lonCR*radian;
SuborbMFD::calcul();
return true;
}

J'ai pas pu tester le code donc y a peut etre un ou deux ajustements, please évite les malloc et separe bien les
bloques dans les fonctions, la premiere partie collecte les données dans des variables clair, la deuxieme devrais pas
avoir à manipuler des pointeurs. C'est dangereux sinon.

Les noms de variable aussi avec les type c'est une bonne habitude:
http://orbiter.dansteph.com/forum/index.php?topic=6344.msg95487#msg95487

J'aurais mis "cBaseName" "hBaseChoisie" (pour handle) enfin tu vois quoi...

Ouais je sais c'est chiant mais faut s'y faire: je donne aussi des conseils :badsmile:

A++

Dan



Message modifié ( 02-08-2008 16:26 )


Offline laserpithium

  • Legend
  • ******
  • Posts: 1473
  • Karma: 0
Reply #5 - 03 August 2008, 01:39:55
Merci beaucoup Dan, ça marche nickel.



La sagesse me cours après, mais je suis plus rapide
Si Dieu existe, butons-le !

Offline DanSteph

  • Administrator
  • Legend
  • *****
  • Posts: 15407
  • Karma: 256
  • Hein, quoi !?
    • FsPassengers
Reply #6 - 03 August 2008, 02:44:19
Pas de quoi, toujours un plaisir.

Note que je le redis c'est pas très convivial d'avoir à taper exactement le nom de base et le pad libre.
C'est dommage de soigner autant l'algo "core" et d'avoir une interface aussi "DOS compliant" :badsmile:
(ligne de commande avec doc sur les genoux pour connaitre la liste valide d'entrée ie: les noms de base)

En plus y a aucune gestion d'erreur donc le gars ce fait jetter sans savoir ou il a fait la couille. Pas de pad ou pas
libre ? nom faux ? mauvais séparateur, espace dans le nom, majuscule, pas de base avec ce nom ?

C'est dommage quoi.. un super algo mais une interface DOS... mais c'est toi qui vois hein :siffle:

A++

Dan


Offline laserpithium

  • Legend
  • ******
  • Posts: 1473
  • Karma: 0
Reply #7 - 03 August 2008, 11:54:34
Quote
DanSteph a écrit:
C'est dommage quoi.. un super algo mais une interface DOS... mais c'est toi qui vois hein :siffle:
Je suis d'accord avec toi. Initialement, je voulais faire un système de liste, un peu comme c'est déjà le cas pour certains
MFD de base d'Orbiter.
Le problème, c'est le temps. Actuellement, je suis en vacances, donc ça va. Mais quand je suis sur mon chantier, c'est 12h
par jours 6 jours sur 7, donc pas énorme de temps pour la prog.
Et en plus mon prochain chantier est en Malaisie... Les mecs là-bas passent leur WE à faire de la plongée sous-marine dans de
la flotte bleue turquoise à 28°C... et les filles ne sont pas farouches...
Donc je risque de vraiment plus avoir beaucoup de temps par la suite !

Du coup, je fais déjà l'indispensable, et ensuite on verra. Mais je suis d'accord avec toi, si seulement j'avais plus de
temps... J'ai plein d'idées...


« Last Edit: 03 August 2008, 11:54:35 by laserpithium »

La sagesse me cours après, mais je suis plus rapide
Si Dieu existe, butons-le !