Fonctions à paramètres infinis

Lap-top Messages postés 56 Date d'inscription   Statut Membre Dernière intervention   -  
Lap-top Messages postés 56 Date d'inscription   Statut Membre Dernière intervention   -
Bonjour tout le monde, je voudrais créer une fonction qui prend une infinité de paramètres (chaines de caractères) et les affiche sur l'écran de la console. J'ai donc essayé ça mais le programme plante à chaque fois, voici le code :

void CfassOut(char *first, ...){
    char* txt = first;
    va_list ap;
    va_start(ap, first);
 
    do  {
        cout << txt << " " ;
        txt = new char[strlen(va_arg(ap, char*)) + 1];
        strcpy(txt, va_arg(ap, char*));
            }while(txt != NULL || strlen(txt) != 0);
            cout << endl;
    va_end(ap);
}


int main()
{
 CfassOut("Nick", "Cephas");  
}


Merci d'avance.

EDIT: Spécification du langage dans la coloration syntaxique.
A voir également:

3 réponses

ElementW Messages postés 4814 Date d'inscription   Statut Contributeur Dernière intervention   1 223
 
'lut, à mon avis le crash vient du fait que tu utilises
va_arg(ap, char*)
deux fois dans ton corps de boucle; or
va_arg()
non seulement retourne l'argument comme tu le souhaites mais passe aussi au suivant. Du coup tu tentes d'accéder au 3e argument, or tu n'en passes pas; va_arg retournerait donc NULL, et strcpy n'apprécie pas.
Il faut donc sauvegarder le pointeur pour ne l'utiliser qu'une fois:
do  {
        cout << txt << " " ;
        char *ptr = va_arg(ap, char*);
        txt = new char[strlen(ptr) + 1];
        strcpy(txt, ptr);
} while(txt != NULL || strlen(txt) != 0);

from human import idiocy
del idiocy
0
Lap-top Messages postés 56 Date d'inscription   Statut Membre Dernière intervention   9
 
Merci pour ta réponse, jai trouvé la solution, aidé par d'autres sur un autre site.
0
sambia39 Messages postés 610 Date d'inscription   Statut Membre Dernière intervention   49
 
Bonsoir
Avez-vous testé le pire des cas ? c'est-à-dire, si je fais ça:
 CfassOut(NULL, NULL); 

Il est clair que les deux programmes fournis dans les postes précédents sont totalement faux et bogué de partout.

Les erreurs mentionné dans le poste précédent sont toujours d'actualité( erreur de programmation & logique ) et rien n'a été corrigé mieux encore vous avez ajouté un bogue supplémentaire.
partant de là =>
 CfassOut(NULL, NULL); 

 size_t strlen( const char *str ) 
renvoi la taille d'une chaine de caractères et @gravgun: va_arg retournerait donc NULL, et strcpy n'apprécie pas.

Donc si ma variable pointeur de type caractère
 char *ptr 
est nul parce que la fonction
va_arg(ap, char*);
ma retourner NULL je n'en tien surtout pas compte et j'alloue tout de même de la mémoire a ma variable pointeur de type char
char* txt = first;
qui ne pointe plus ( désormais) sur premier argument de ma fonction
 void CfassOut(char *first, ...); 
dont celle-ci (
char* txt
), réserve bien NULL comme taille mémoire souhaité que je tiens toujours pas compte pour ensuite copier le contenue de ma variable pointeur
ptr
dans le variable pointeur
 txt 
et au final comme en teste au moins une fois en est sûr que ça va marcher dans les cas suivant ? :

CfassOut(NULL,NULL);   //bogue
CfassOut(NULL,"BONJOUR");  //bogue
/* Compilateur en mode stricte j'obtiens
 *  deprecated conversion from string constant to `char*' [-Werror=write-strings]
 */
CfassOut("BONJOUR",NULL); //bogue
CfassOut("SALUT","S39"); //bogue

/* cast en (char *) */
CfassOut((char*)"BONJOUR",NULL); //bogue
CfassOut((char*)"SALUT","S39"); //bogue


Bref, la fonction doit avoir ce qu'on appelle une sentinelle ou une save flag en clair, elle nous permet de savoir exactement combien d'argument ont été passé ou spécifier l'arrêt du traitement à l'aide d'une valeur spéciale en tant que derniers arguments de plus le premier argument fixe de notre fonction n'est pas utilisé mais pour c'est genre de fonction, il nous faut au moins un argument.
Au final si on suit cette logique, nous devons avoir une fonction qui affichage toutes les chaines de caractère passé en argument jusqu'à la dernière qui doit être NULL

#include <cstdlib>
#include <cstdarg>
#include <iostream>

/* Fonction multi-argument */
void cFass_Correct( void *p, ... ){

 va_list v_list;
 va_start( v_list , p );
 char *p_str = NULL;

 while( (p_str = va_arg( v_list, char* ) ) != NULL ){
  std::cout << "[ARG]\t:" << p_str << std::endl;
  p_str = NULL;
 }
}

/* Fonction principal */
int main( void ){

 /* Teste */
 cFass_Correct( NULL, NULL );
 cFass_Correct( NULL, "BONJOUR", NULL );
 cFass_Correct( NULL, "BONJOUR\n", "S39", NULL );
 cFass_Correct( NULL, "BONJOUR", NULL, "S39" ); /* affiche bonjour */
 cFass_Correct( (char*)"BONJOUR", NULL );
 cFass_Correct( (char*)"BONJOUR", "S39", NULL );

 return ( EXIT_SUCCESS );
}

à bientôt
Celui qui peut, agit. Celui qui ne peut pas, enseigne.
Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien, et les philosophes, qui ne connaissent rien sur tout.
George Bern
0
Lap-top Messages postés 56 Date d'inscription   Statut Membre Dernière intervention   9
 
Là, c'est une explication de taille. Vraiment merci d'avoir pris la peine de me le détailler de la sorte. Bye
0