Utilisation de printf avec une chaîne terminée non nulle


107

Supposons que vous ayez une chaîne qui n'est PAS nullterminée et que vous connaissez sa taille exacte, alors comment pouvez-vous imprimer cette chaîne avec printfen C? Je me souviens d'une telle méthode mais je ne peux pas la découvrir maintenant ...


9
Dans le Ccontexte, toutes les chaînes sont terminées par null. Les tableaux de char sans null ne sont pas des chaînes ... ce sont des tableaux de char :)
pmg


Réponses:


174

Il y a une possibilité avec printf, ça va comme ça:

printf("%.*s", stringLength, pointerToString);

Pas besoin de copier quoi que ce soit, pas besoin de modifier la chaîne ou le tampon d'origine.


10
Mais de toute façon c'est dangereux, quelqu'un imprimera un jour cette chaîne avec% s
pmod

6
@Pmod: Pas nécessairement si le tampon n'est pas exposé au monde extérieur. Il est également très utile de n'imprimer que des parties d'une chaîne (qui peut être terminée par null, bien sûr). Si vous voulez vraiment voir cela en action, jetez un œil au proxy SIP OpenSER / Kamailio où ils évitent beaucoup de copier des choses à cause de cette technique (également en utilisant sprintf).
DarkDust

6
un autre +1. J'adore quand j'apprends des choses sur des choses basiques comme printfmême après une ~ décennie ... :)
Hertzel Guinness

1
Pour moi, c'est très utile lorsque je reçois une chaîne terminée non nulle d'une API (certaines API Windows le font!) Et que je dois la renvoyer d'une manière «raisonnable». Donc: longue vie à%. * S (ou%. * S qui fera également la conversion UNICODE <-> SINGLE-BYTE pour vous!;))
FrizzTheSnail

3
@ user1424739: Dans votre cas, printfil imprimera jusqu'à 11 caractères ou jusqu'à ce qu'il rencontre NULL, selon la première éventualité; dans votre exemple, NULL vient en premier. Spécifier une longueur maximale ne fait pas perdre à NULL sa signification de «fin de chaîne» pour printf.
DarkDust

29

Voici une explication de la façon dont %.*sfonctionne et où il est spécifié.

Les spécifications de conversion dans une chaîne de modèle printf ont la forme générale:

% [ param-no $] flags width [ . precision ] type conversion

ou

% [ param-no $] flags width . * [ param-no $] type conversion

La deuxième forme est pour obtenir la précision de la liste d'arguments:

Vous pouvez également spécifier une précision de «*». Cela signifie que l'argument suivant dans la liste d'arguments (avant la valeur réelle à imprimer) est utilisé comme précision. La valeur doit être un entier et est ignorée si elle est négative.

Syntaxe de conversion de sortie dans le manuel de la glibc

Pour %sle formatage de chaîne, la précision a une signification particulière:

Une précision peut être spécifiée pour indiquer le nombre maximum de caractères à écrire; sinon, les caractères de la chaîne jusqu'au caractère nul de fin, mais non compris, sont écrits dans le flux de sortie.

Autres conversions de sortie dans le manuel de la glibc

Autres variantes utiles:

  • "%*.*s", maxlen, maxlen, val justifie à droite, en insérant des espaces avant;
  • "%-*.*s", maxlen, maxlen, val justifiera à gauche.

Si je comprends bien, ce qui suit remplirait la sortie tout en empêchant tout débordement de chaîne? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

Vous pouvez utiliser un fwrite () pour stdout!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

De cette façon, vous sortirez les premiers caractères (nombre défini dans la variable number_of_chars) dans un fichier, dans ce cas vers stdout (la sortie standard, votre écran)!


2
Très utile lorsque vous souhaitez inspecter un long tampon contenant des chaînes et des zéros!
Elist du

13

printf("%.*s", length, string) ne fonctionnera pas.

Cela signifie imprimer jusqu'à TO octets de longueur OU un octet nul, selon la première éventualité. Si votre tableau de caractères non terminé par un caractère nul contient des octets nuls AVANT la longueur, printf s'arrêtera sur ceux-ci et ne continuera pas.


4
Et en quoi est-ce une réponse à la question du PO?
Shahbaz

12
s'il n'est pas terminé par null, alors null est un caractère valide que la chaîne doit contenir. cela pense toujours que le tableau est terminé par un nul, il le traite simplement comme un tableau plus long dans lequel il sous-sélectionne - ce qui signifie que si vous avez une chaîne avec des valeurs nulles, cela posera des problèmes.
lahwran

3
printf("%.5s", pointerToNonNullTerminatedString);

La longueur de la chaîne sera de 5.


1
#include<string.h> 
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
 int i;
 for(i=0;i<n;i++)
 {
 printf("%c",str[i]);
 }
 return 0;
}

J'ai édité le code, voici une autre façon:

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}

Très mauvaises performances en raison de nombreuses lectures d'octets inutiles (ce qui entraîne une pénalité de performances si l'octet n'est pas sur une adresse alignée sur les mots sur la plupart des processeurs) et l'analyse du formatage et l'application sont également effectuées pour chaque caractère. Ne faites pas cela :-) Voir ma réponse pour la solution.
DarkDust

@DarkDust: seule une machine pathologique pénaliserait les lectures d'octets non alignées sur les limites des mots. Pensez-vous à des lectures de mots non alignées sur les limites des mots? Ou une vieille merde de mips ou quelque chose comme ça?
R .. GitHub STOP HELPING ICE

@R ..: Si vous considérez que le système x86 est endommagé et obsolète, je suis tout à fait d'accord. Parce que x86 a une pénalité pour la lecture et l'écriture de mémoire non alignée sur des mots. ARM aussi. Voir par exemple cette question ou cette question . Le fait est (si j'ai bien compris) que les données sont extraites de la mémoire en blocs de taille de mot et que l'obtention du bon octet est un autre micro-op. Ce n'est pas grave, mais dans une boucle énorme, cela pourrait faire une différence.
DarkDust

@DarkDust: vous vous trompez complètement à ce sujet pour les lectures d'octets. Pourquoi n'allez-vous pas faire un benchmark? x86 a des opérations d'octet complètement atomiques et a toujours eu. Il ne récupère pas les morceaux de taille de mot (sauf au niveau du cache, qui récupère des morceaux beaucoup plus gros et l'alignement n'est pas pertinent, mais je parle de données déjà mises en cache).
R .. GitHub STOP HELPING ICE

@DarkDust: PS3 ne prend pas en charge la lecture ou l'écriture d'octets non alignés sur SPU. En fait, il ne prend même pas en charge les types scalaires, il n'y a que des vecteurs, qui doivent être alignés. Le compilateur les émule. Et de nombreux processeurs ARM ne prennent pas en charge la lecture ou l'écriture d'octets, mais n'effectuent que la lecture ou l'écriture de mots.
Sylvain Defresne
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.