Verwenden von printf mit einer nicht nullterminierten Zeichenfolge


107

Angenommen, Sie haben eine Zeichenfolge, die NICHT nullterminiert ist, und Sie kennen die genaue Größe. Wie können Sie diese Zeichenfolge printfin C drucken ? Ich erinnere mich an eine solche Methode, kann sie aber jetzt nicht herausfinden ...


9
Im CKontext sind alle Zeichenfolgen nullterminiert. Arrays von char ohne eine Null in ihnen sind keine Strings ... sie sind Arrays von char :)
pmg


Antworten:


174

Es gibt eine Möglichkeit mit printf, es geht so:

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

Sie müssen nichts kopieren, die ursprüngliche Zeichenfolge oder den ursprünglichen Puffer müssen nicht geändert werden.


10
Aber trotzdem ist es gefährlich, irgendwann wird jemand diesen String mit% s
pmod

6
@Pmod: Nicht unbedingt, wenn der Puffer nicht der Außenwelt ausgesetzt ist. Es ist auch sehr nützlich, nur Teile einer Zeichenfolge zu drucken (die natürlich nullterminiert sein können). Wenn Sie dies wirklich in Aktion sehen möchten, schauen Sie sich den OpenSER / Kamailio SIP-Proxy an, in dem das Kopieren von Inhalten aufgrund dieser Technik häufig vermieden wird (auch mit sprintf).
DarkDust

6
ein weiteres +1. Ich liebe es, wenn ich Dinge über grundlegende Dinge lerne, wie printfauch nach einem Jahrzehnt ... :)
Hertzel Guinness

1
Für mich ist es sehr nützlich, wenn ich eine nicht nullterminierte Zeichenfolge von einer API erhalte (einige Windows-APIs tun dies!) Und sie auf eine "vernünftige" Weise zurückgeben muss. Also: lange Lebensdauer auf%. * S (oder%. * S, wodurch auch die Konvertierung UNICODE <-> SINGLE-BYTE für Sie macht !;))
FrizzTheSnail

3
@ user1424739: In Ihrem Fall printfwerden bis zu 11 Zeichen gedruckt oder bis NULL angezeigt wird , je nachdem, was zuerst eintritt . In Ihrem Beispiel steht NULL an erster Stelle. Wenn Sie eine maximale Länge angeben, verliert NULL nicht die Bedeutung für "Ende der Zeichenfolge" für printf.
DarkDust

29

Hier finden Sie eine Erklärung, wie es %.*sfunktioniert und wo es angegeben ist.

Die Konvertierungsspezifikationen in einer printf-Vorlagenzeichenfolge haben die allgemeine Form:

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

oder

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

Die zweite Form dient zum Abrufen der Genauigkeit aus der Argumentliste:

Sie können auch eine Genauigkeit von '*' angeben. Dies bedeutet, dass das nächste Argument in der Argumentliste (vor dem tatsächlich zu druckenden Wert) als Genauigkeit verwendet wird. Der Wert muss ein int sein und wird ignoriert, wenn er negativ ist.

Ausgabekonvertierungssyntax im glibc-Handbuch

Bei der %sFormatierung von Zeichenfolgen hat die Genauigkeit eine besondere Bedeutung:

Es kann eine Genauigkeit angegeben werden, die die maximale Anzahl der zu schreibenden Zeichen angibt. Andernfalls werden Zeichen in der Zeichenfolge bis einschließlich des abschließenden Nullzeichens in den Ausgabestream geschrieben.

Andere Ausgabekonvertierungen im glibc-Handbuch

Andere nützliche Varianten:

  • "%*.*s", maxlen, maxlen, val rechtfertigt das Einfügen von Leerzeichen vor;
  • "%-*.*s", maxlen, maxlen, val wird links rechtfertigen.

Wenn ich das richtig verstehe, würde das Folgende die Ausgabe auffüllen und dennoch einen Stringüberlauf verhindern? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

Sie können ein fwrite () verwenden, um zu stdout!

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

Auf diese Weise geben Sie die ersten Zeichen (in der Variablen number_of_chars definierte Nummer) in eine Datei aus, in diesem Fall in stdout (die Standardausgabe, Ihr Bildschirm)!


2
Sehr hilfreich, wenn Sie einen langen Puffer mit Zeichenfolgen und Nullen untersuchen möchten!
Elist

13

printf("%.*s", length, string) wird nicht funktionieren.

Dies bedeutet, dass bis zu Längenbytes ODER ein Nullbyte gedruckt werden, je nachdem, was zuerst eintritt. Wenn Ihr nicht nullterminiertes Zeichenarray vor der Länge null Bytes enthält, stoppt printf auf diesen und fährt nicht fort.


4
Und wie ist das eine Antwort auf die Frage des OP?
Shahbaz

12
Wenn es nicht nullterminiert ist, ist null ein gültiges Zeichen für die Zeichenfolge. Dies bedeutet immer noch, dass das Array nullterminiert ist. Es behandelt es lediglich als ein längeres Array, aus dem es untergewählt wird. Wenn Sie also eine Zeichenfolge mit Nullen haben, führt dies zu Problemen.
Lahwran

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

Die Stringlänge beträgt 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;
}

Ich habe den Code bearbeitet, hier ist eine andere Möglichkeit:

#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;

}

Sehr schlechte Leistung aufgrund vieler unnötiger Byte-Lesevorgänge (die mit einer Leistungsbeeinträchtigung verbunden sind, wenn sich das Byte auf den meisten CPUs nicht an einer wortausgerichteten Adresse befindet) und auch das Parsen und Anwenden der Formatierung erfolgt für jedes einzelne Zeichen. Tu das nicht :-) Siehe meine Antwort für die Lösung.
DarkDust

@DarkDust: Nur eine pathologische Maschine würde Byte-Lesevorgänge bestrafen, die nicht an Wortgrenzen ausgerichtet sind. Denken Sie an Wortlesungen, die nicht an Wortgrenzen ausgerichtet sind? Oder irgendein uralter Mips-Mist oder so?
R .. GitHub STOP HELPING ICE

@R ..: Wenn Sie x86 als hirngeschädigt und veraltet betrachten, stimme ich absolut zu. Weil x86 eine Strafe für das Lesen und Schreiben von nicht wortausgerichtetem Speicher hat. ARM auch. Siehe zum Beispiel diese Frage oder diese Frage . Die Sache ist (wenn ich das richtig verstanden habe), dass Daten in wortgroßen Blöcken aus dem Speicher abgerufen werden und das richtige Byte ein weiteres Mikro-Op ist. Keine große Sache, aber in einer großen Schleife könnte es einen Unterschied machen.
DarkDust

@ DarkDust: Sie sind völlig falsch in Bezug auf Byte-Lesevorgänge. Warum machst du keinen Benchmark? x86 hat vollständig atomare Byte-Operationen und hatte es immer. Es werden keine wortgroßen Chunks abgerufen (außer auf Cache-Ebene, wo viel größere Chunks abgerufen werden und die Ausrichtung irrelevant ist, aber ich spreche von bereits zwischengespeicherten Daten).
R .. GitHub STOP HELPING ICE

@DarkDust: PS3 unterstützt das Lesen oder Schreiben von nicht ausgerichteten Bytes auf SPU nicht. Tatsächlich werden nicht einmal Skalartypen unterstützt, es gibt nur Vektoren, die ausgerichtet werden müssen. Der Compiler emuliert sie. Und viele ARM-Prozessoren unterstützen kein Lesen oder Schreiben von Bytes, sondern führen nur das Lesen oder Schreiben von Wörtern durch.
Sylvain Defresne
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.