Utilizzo di printf con una stringa con terminazione non nulla


107

Supponi di avere una stringa che NON è nullterminata e di conoscere la sua dimensione esatta, quindi come puoi stampare quella stringa con printfin C? Ricordo un metodo del genere ma non riesco a scoprirlo ora ...


9
Nel Ccontesto, tutte le stringhe sono terminate con null. Gli array di char senza null non sono stringhe ... sono array di char :)
pmg


Risposte:


174

C'è una possibilità con printf, funziona così:

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

Non è necessario copiare nulla, non è necessario modificare la stringa o il buffer originale.


10
Ma comunque è pericoloso, qualcuno un giorno stamperà questa stringa con% s
pmod

6
@Pmod: non necessariamente se il buffer non è esposto al mondo esterno. È anche molto utile stampare solo parti di una stringa (che può terminare con null, ovviamente). Se vuoi davvero vederlo in azione, dai un'occhiata al proxy SIP OpenSER / Kamailio dove evitano di copiare cose a causa di questa tecnica molto (anche usando sprintf).
DarkDust,

6
un altro +1. Mi piace quando imparo cose su cose di base come printfanche dopo un ~ decennio ... :)
Hertzel Guinness

1
Per me è molto utile quando ricevo una stringa con terminazione non nulla da un'API (alcune API di Windows lo fanno!) E devo restituirla in un modo "ragionevole". Quindi: lunga vita a%. * S (o%. * S che farà anche la conversione UNICODE <-> SINGLE-BYTE per te!;))
FrizzTheSnail

3
@ user1424739: nel tuo caso printfstamperà fino a 11 caratteri o fino a quando non incontra NULL, a seconda dell'evento che si verifica per primo; nel tuo esempio NULL viene prima. Specificare una lunghezza massima non fa perdere a NULL il significato di "fine stringa" per printf.
DarkDust,

29

Ecco una spiegazione di come %.*sfunziona e dove è specificato.

Le specifiche di conversione in una stringa di modello printf hanno la forma generale:

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

o

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

La seconda forma serve per ottenere la precisione dall'elenco degli argomenti:

È inoltre possibile specificare una precisione di "*". Ciò significa che l'argomento successivo nell'elenco degli argomenti (prima del valore effettivo da stampare) viene utilizzato come precisione. Il valore deve essere un int e viene ignorato se è negativo.

Sintassi di conversione dell'output nel manuale glibc

Per %sla formattazione delle stringhe, la precisione ha un significato speciale:

È possibile specificare una precisione per indicare il numero massimo di caratteri da scrivere; altrimenti i caratteri nella stringa fino al carattere null di terminazione, ma escluso, vengono scritti nel flusso di output.

Altre conversioni di output nel manuale di glibc

Altre varianti utili:

  • "%*.*s", maxlen, maxlen, val giustificherà a destra, inserendo spazi prima;
  • "%-*.*s", maxlen, maxlen, val giustificherà a sinistra.

Se capisco correttamente, quanto segue riempirebbe l'output e tuttavia impedirebbe un overflow di stringa? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

Puoi usare fwrite () per stdout!

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

In questo modo emetterete i primi caratteri (numero definito nella variabile number_of_chars) in un file, in questo caso in stdout (lo standard output, il vostro schermo)!


2
Molto utile quando si desidera ispezionare un lungo buffer contenente stringhe e zeri!
Elist

13

printf("%.*s", length, string) non funzionerà.

Ciò significa stampare FINO A lunghezza byte O un byte nullo, a seconda di quale si verifica per primo. Se il tuo array di caratteri con terminazione non nullo contiene byte nulli PRIMA della lunghezza, printf si fermerà su quelli e non continuerà.


4
E come è questa una risposta alla domanda dell'OP?
Shahbaz

12
se non ha terminazione null, null è un carattere valido per la stringa da contenere. questo pensa ancora che l'array sia terminato da null, lo tratta semplicemente come un array più lungo da cui è sotto-selezione - il che significa che se hai una stringa con null in esso, ciò causerà problemi.
lahwran

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

La lunghezza della stringa sarà 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;
}

Ho modificato il codice, ecco un altro modo:

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

}

Prestazioni pessime a causa di molte letture di byte non necessarie (che comportano una penalizzazione delle prestazioni se il byte non si trova su un indirizzo allineato a parole sulla maggior parte delle CPU) e anche l'analisi e l'applicazione della formattazione vengono eseguite per ogni carattere. Non farlo :-) Vedi la mia risposta per la soluzione.
DarkDust,

@DarkDust: solo una macchina patologica penalizzerebbe le letture di byte non allineate ai confini delle parole. Stai pensando a letture di parole non allineate ai confini delle parole? O qualche vecchia merda di mips o qualcosa del genere?
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO

@R ..: Se consideri x86 cerebralmente danneggiato e obsoleto, sono assolutamente d'accordo. Perché x86 ha una penalità per la lettura e la scrittura di memoria non allineata a parole. Così fa ARM. Vedi ad esempio questa domanda o questa domanda . Il fatto è (se l'ho capito correttamente) che i dati vengono recuperati in blocchi di dimensioni di parola dalla memoria e ottenere il byte corretto è un altro micro-op. Non è un grosso problema, ma in un ciclo enorme potrebbe fare la differenza.
DarkDust,

@ DarkDust: ti sbagli completamente su questo per le letture di byte. Perché non vai a fare un benchmark? x86 ha operazioni byte completamente atomiche e lo ha sempre avuto. Non recupera blocchi di dimensioni di parola (tranne a livello di cache, che recupera blocchi molto più grandi e l'allineamento è irrilevante, ma sto parlando di dati già memorizzati nella cache).
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO

@DarkDust: PS3 non supporta la lettura o la scrittura di byte non allineati su SPU. Infatti non supporta nemmeno i tipi scalari, ci sono solo vettori, che devono essere allineati. Il compilatore li emula. E molti processori ARM non supportano la lettura o la scrittura di byte, ma eseguono solo la lettura o la scrittura di parole.
Sylvain Defresne
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.