2010-01-07 5 views
3

A écrit une fonction C très simple pour illustrer ce que je voudrais simplifier:Ajoute la chaîne formatée à la chaîne en C (pas C++) sans arithmétique de pointeur?

void main(int argc, char *argv[]){ 
    char *me="Foo"; 
    char *you="Bar"; 
    char us[100]; 
    memset(us,100,0x00); 

    sprintf(us,"You: %s\n",you); 
    sprintf(us+strlen(us),"Me: %s\n",me); 
    sprintf(us+strlen(us),"We are %s and %s!\n",me,you); 
    printf(us); 
} 

Il semble qu'il devrait y avoir une fonction de bibliothèque standard pour gérer ce que je fais avec sprintf et faire avancer le pointeur, non? A été années depuis que je l'ai fait toute quantité de C ...

Merci, -aj

+1

"il semble qu'il devrait y avoir une fonction de bibliothèque standard", le c stdlib n'est pas aussi étendu que dans d'autres langages comme Java dis :) donc je doute qu'il y ait – hhafez

+0

@hhafez, Spot on; faire la transition vers la pensée en C (vs Python et Java) est exactement où je suis. –

Répondre

8

sprintf renvoie le nombre de caractères non NUL écrits.

int len = 0; 
len += sprintf(us+len, ...); 
len += sprintf(us+len, ...); 
... 
+0

Ha, je suppose que c'est un peu plus bref, mais en accomplissant toujours la même chose. –

+6

Non. Votre exemple appelle strlen() pour chaque itération, ce qui fait d'O (N^2) le nombre d'appels de sprintf(). Cela profite du fait que la famille de fonctions printf retourne le nombre de caractères imprimés pour obtenir le résultat de strlen gratuitement. C'est, en fait, l'idiome standard pour ce genre de chose. Et comme toujours: assurez-vous de tester la longueur de votre tampon et d'utiliser snprintf si c'est quelque chose qui gérera des données non fiables! –

+0

@Andy, bonnes pensées, merci! –

1

Vous cherchez probablement strcat (ou mieux encore strncat).

+0

Hrrm ... pour une chaîne formatée ...? –

+0

Formatez-le d'abord, puis effectuez la concaténation. – kgiannakakis

+0

Donc, en utilisant plusieurs tampons alors ... non? –

1
char *me="Foo"; 
char *you="Bar"; 
char us[100]; 

char* out = us; 
out += sprintf(out,"You: %s\n",you); 
out += sprintf(out,"Me: %s\n",me); 
out += sprintf(out,"We are %s and %s!\n",me,you); 
printf("%s", us); 
+3

Veuillez ne pas 'printf (us)': 'printf ("% s ", us)' et 'fputs (us, stdout)' sont beaucoup plus sûrs. – ephemient

+1

Sans se soucier de la question, sprintf() est aussi mauvais. Mis à jour, merci. –

+0

'sprintf' va bien aussi longtemps que vous êtes confiant dans la taille de vos tampons. D'un autre côté, 'printf (us)' passe une analyse de travail supplémentaire pour '%' même si c'est sûr et il ne devrait y en avoir aucun. – ephemient

2

Hmm ... ne pouvez-vous utiliser quelque chose comme:

sprintf(us, "You: %s\nMe: %s\nWe are %s and %s!\n, you, me, me, you); 
+1

ou pour les systèmes compatibles SUS: 'sprintf (us," Vous:% 1 $ s \ nMe:% 2 $ s \ nNous sommes% 2 $ s et% 1 $ s! \ N ", vous, moi);' – dreamlax

1

Ne jamais utiliser une chaîne non constante comme premier argument à printf (ou second argument fprintf. Essayez de changer la variable me en "Muahaha %n%d%n%d%n%d%n%d%n" et dites au revoir à votre pile et dites bonjour à SEGFAULTprintf va essayer de formater la chaîne mais vous n'avez fourni aucun argument pour qu'elle Avec, et même s'il existe des spécificateurs de format dans la chaîne, printf n'a aucune idée que vous ne lui avez pas donné d'arguments.

Si vous souhaitez générer une chaîne "pré-formatée", utilisez fputs(str,stdout). Il est rarement possible d'utiliser printf avec une chaîne de format non constante.

+1

@hhafez, non, dreamlax dit que l'utilisation d'une chaîne autre qu'un littéral est dangereuse, car elle pourrait contenir des spécificateurs de format pour lesquels vous n'avez pas passé d'arguments, invoquant un comportement indéfini.Ceci est une plus grande préoccupation quand il s'agit de l'entrée de l'utilisateur, car cela vous ouvre aux attaques (ne jamais appeler printf (str) sur l'entrée de l'utilisateur) mais aussi un problème si votre programme génère la mauvaise chaîne de format. –

+0

@hahafez: 'printf' est utilisé pour imprimer une chaîne formatée ** basée sur une chaîne de description de format et des arguments fournis **. Lorsque vous fournissez une chaîne pré-formatée et aucun argument, vous n'utilisez pas 'printf' correctement. Lorsque vous voulez générer une chaîne verbatim, utilisez une fonction dédiée à cet effet, par exemple 'fputs'. Si vous utilisez 'printf' pour sortir des chaînes pré-formatées non-constantes, vous courez le risque de dire' printf' pour formater à nouveau des parties de la chaîne. Un utilisateur malveillant peut fournir des spécificateurs de format en entrée (tels que '% n' et'% d') et votre application tomberait certainement en panne. – dreamlax

+0

complètement mal lu la réponse, merci pour l'explication – hhafez