2011-03-02 14 views
6

È un puntatore NULL consentito come stringa da memorizzare in una chiamata a sscanf? Non trovo nulla a riguardo nella documentazione, ma sembra che funzioni bene. Stessa cosa con scanf.Argomento NULL permesso a sscanf?

Esempio:

int main(int arc, char* argv[]) 
{ 
    char* s = NULL; 
    sscanf("Privjet mir!", "%s", s); 
    printf("s: %s\n", s); 
    return 0; 
} 

uscita: s: (null)

risposta

6

No:

corrisponde ad una successione di non-white-space caratteri; il puntatore successivo deve essere un puntatore nell'array di caratteri che è lungo il tempo necessario per contenere la sequenza di input e il carattere nullo terminante ('\ 0'), che viene aggiunto automaticamente. La stringa di input si arresta allo spazio bianco o alla larghezza massima del campo, , a seconda della condizione che si verifica per prima.

(http://linux.die.net/man/3/sscanf)

+0

Questa risposta ci insegna anche che proibire null non ha bisogno di menzionare esplicitamente la parola "null".Affermando che qualcosa deve essere "un puntatore a " vieta implicitamente il nulla. – Lii

1

La pagina del manuale dice che, quando si utilizza %s, l'argomento deve essere un puntatore con spazio sufficiente per la stringa e \0. Quindi la mia ipotesi sarebbe che il comportamento nel tuo caso non è definito. Potrebbe funzionare, potrebbe anche bloccarsi o corrompere la memoria e causare problemi in seguito.

1

No, questo non è consentito. sscanf% s si aspetta un char * che punta a un buffer sufficientemente grande, printf% s vuole un buffer nul char *. Qualsiasi altra cosa comporta un comportamento indefinito. (E questo significa che alcune implementazioni potrebbero rilevare e gestire un puntatore nullo in un certo modo, altre implementazioni non potrebbe)

1

non ho trovato nulla in principio circa esplicitamente NULL e *printf/*scanf.

Suppongo che questo è un comportamento indefinito , dal momento che conta come il passaggio di un argomento che non è coerente con l'identificatore di formato (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s significa che una si passa un puntatore al primo elemento di un array di caratteri (abbastanza grande per la stringa acquisita per *scanf, contenente una stringa terminata NUL per *printf) e il passaggio di NULL non soddisfa questo requisito.


1. In questo caso UB mostra come "solo ignorando l'acquisizione" e "stampa (null)", su altre piattaforme esso può comportare piani cadono cielo o il solito nasal demons.

-2

Assegnare la memoria a s. Assegna s alla matrice di caratteri. Quindi esegui il programma. In seguito funzionerà.

int main(int arc, char* argv[]) 
{ 
    char s[100]; 
    sscanf("Privjet mir!", "%[^\t]s", s); 
    printf("s: %s\n", s); 
    return 0; 
} 
+0

Non risponde davvero alla mia domanda ... – Lii

4

Come è menzionato dalle altre risposte NULL non è valida per passare a sscanf come un ulteriore argomento.

http://www.cplusplus.com/reference/cstdio/sscanf dice di ulteriori argomenti

seconda della stringa di formato, la funzione può aspettarsi una sequenza di argomenti aggiuntivi, ciascuno contenente un puntatore di memoria allocata quando l'interpretazione dei caratteri estratti viene memorizzata con il tipo appropriato.

For the %s specifier these extracted characters are:

qualsiasi numero di caratteri che non sono spazi, fermandosi al primo carattere spazio bianco trovato. Un carattere nullo terminante viene aggiunto automaticamente alla fine della sequenza memorizzata.

Così quando sono memorizzati i "caratteri non di spaziatura" e "carattere nullo di fine", ci sarà un segfault. Il che è esattamente ciò che Visual Studio produrrà (è possibile verificare che questo non riesce a http://webcompiler.cloudapp.net/):

enter image description here

Ora per quanto non Visual Studio compilatori, il codice di estrazione di libc per la %s identificatore: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 ha il leader commento: /* We might have to handle the allocation ourselves */ questo perché:

la libreria GNU C supportato l'indicatore di conversione allocazione dinamica (come estensione non standard) tramite il carattere a. Questa funzione sembra essere presente almeno fino a quella di glibc 2.0.
Dalla versione 2.7, glibc fornisce anche il modificatore m per lo stesso scopo del modificatore a.

[Source]

Quindi, a causa estratti libc ad un buffer costruiti internamente per sscanf e, successivamente, controlla che il parametro di buffer non ha bandiere impostato prima di assegnarlo, non potrà mai scrivere i caratteri di un parametro NULL buffer.

Non posso sottolineare abbastanza che questo non è standard e non è garantito che venga mantenuto anche tra gli aggiornamenti di librerie minori. Un modo di gran lunga migliore per farlo è quello di utilizzare la * sub-specificatore cui:

Indica che i dati devono essere letti dal flusso ma ignorato (cioè non viene memorizzato nella posizione indicata da un argomento) .

[Source]

Ciò potrebbe essere realizzato in questo modo, per esempio:

s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s); 

Ovviamente il vero ramo del ternario è un no-op, ma ho incluso con l'aspettativa che altri dati dovessero essere letti dalla stringa.

Problemi correlati