scanf-formatsträng
En scanf-formatsträng ( skanningsformaterad ) är en kontrollparameter som används i olika funktioner för att specificera layouten för en inmatningssträng . Funktionerna kan sedan dela upp strängen och översättas till värden av lämpliga datatyper . Strängskanningsfunktioner tillhandahålls ofta i standardbibliotek . Scanf är en funktion som läser formaterad data från standardinmatningssträngen, som vanligtvis är tangentbordet och skriver resultaten närhelst de anropas i de angivna argumenten.
Termen "scanf" kommer från C-biblioteket , som populariserade denna typ av funktion, men sådana funktioner är före C, och andra namn används, såsom readf
i ALGOL 68 . scanf-formatsträngar, som tillhandahåller formaterad indata ( parsing ), är komplementära till printf-formatsträngar , som ger formaterad utdata ( templating ). Dessa ger enkel funktionalitet och fast format jämfört med mer sofistikerade och flexibla parsers eller mallmotorer, men är tillräckliga för många ändamål.
Historia
Mike Lesks portabla in-/utdatabibliotek , inklusive scanf
, blev officiellt en del av Unix i version 7 .
Användande
Scanf -
funktionen, som finns i C , läser indata för siffror och andra datatyper från standardinmatning (ofta ett kommandoradsgränssnitt eller liknande typ av textanvändargränssnitt ).
Följande C-kod läser ett variabelt antal oformaterade decimaltal från standardinmatningsströmmen och skriver ut var och en av dem på separata rader:
0
#include <stdio.h> int main ( void ) { int n ; while ( scanf ( "%d" , & n ) == 1 ) printf ( "%d \n " , n ); återvända ; }
Efter att ha bearbetats av programmet ovan visas en oregelbundet fördelad lista med heltal som t.ex
456 123 789 456 12 456 1 2378
kommer att visas konsekvent fördelade som:
456 123 789 456 12 456 1 2378
Så här skriver du ut ett ord:
0
#include <stdio.h> int main ( void ) { char word [ 20 ]; if ( scanf ( "%19s" , word ) == 1 ) sätter ( word ); återvända ; }
Oavsett vilken datatyp programmeraren vill att programmet ska läsa, måste argumenten (som &n
ovan) vara pekare som pekar mot minnet. Annars kommer funktionen inte att fungera korrekt eftersom den kommer att försöka skriva över fel delar av minnet, snarare än att peka på minnesplatsen för variabeln du försöker få indata för.
I det sista exemplet används inte en adress-of-operator ( &
) för argumentet: eftersom ord
är namnet på en array av char
, som sådan är det (i alla sammanhang där det evalueras till en adress) ekvivalent med en pekare till det första elementet i arrayen. Medan uttrycket &ord
skulle numeriskt utvärderas till samma värde, har det semantiskt en helt annan betydelse genom att det står för adressen till hela arrayen snarare än ett element av det. Detta faktum måste komma ihåg när du tilldelar scanf-
utdata till strängar.
Eftersom scanf
är avsett att endast läsa från standardinmatning, har många programmeringsspråk med gränssnitt , som PHP , derivator som sscanf
och fscanf
men inte scanf
i sig.
Formatsträngsspecifikationer
Formateringsplatshållarna i scanf
är mer eller mindre desamma som i printf
, dess omvända funktion. Som i printf är POSIX-tillägget n$
definierat.
Det finns sällan konstanter (dvs. tecken som inte är formaterande platshållare ) i en formatsträng, främst för att ett program vanligtvis inte är utformat för att läsa känd data, även om scanf
accepterar dessa om det uttryckligen anges. Undantaget är ett eller flera blanksteg , vilket tar bort alla blanksteg i inmatningen.
Några av de vanligaste platshållarna följer:
-
%a
: Skanna ett flyttal i dess hexadecimala notation. -
%d
: Skanna ett heltal som ett decimaltal med tecken . -
0
%i
: Skanna ett heltal som ett signerat tal. Liknar%d
, men tolkar talet som hexadecimalt när det föregås av0x
och oktalt när det föregås av . Till exempel skulle strängen031 läsas som 31 med
%d
och 25 med%i
. Flagganh
i%hi
indikerar konvertering till enkort
ochhh
konvertering till enchar
. -
%u
: Sök efter decimalutan tecken int
(Observera att i C99-standarden är inmatningsvärdet minustecken valfritt, så om ett minustecken läses uppstår inga fel och resultatet blir de tvås komplement till ett negativt tal, troligen ett mycket stort värde Sestrtoul ()
[ misslyckad verifiering ] ) På motsvarande sätt söker%hu
efter enosignerad kortslutning
och%hhu
efter enosignerad char
. -
%f
: Skanna ett flyttalstal i normal ( fast punkt ) notation. -
%g
,%G
: Skanna ett flyttal i antingen normal eller exponentiell notation.%g
använder små bokstäver och%G
använder versaler. -
%x
,%X
: Skanna ett heltal som ett hexadecimalt tal utan tecken. -
%o
: Skanna ett heltal som ett oktalt tal. -
%s
: Skanna en teckensträng . Skanningen avslutas vid blanksteg . Ett nolltecken lagras i slutet av strängen, vilket innebär att bufferten som tillhandahålls måste vara minst ett tecken längre än den angivna inmatningslängden. -
%c
: Skanna ett tecken (char). Inget nolltecken läggs till. - blanksteg : Alla blanktecken utlöser en genomsökning efter noll eller fler blanksteg . Antalet och typen av blanktecken behöver inte matcha i någon av riktningarna.
-
%lf
: Skanna som ett dubbelt flyttal. "Flytande"-format med "lång"-specifikationen. -
%Lf
: Skanna som ett långt dubbelt flyttal. "Float" formaterar "lång lång" specifikationen. -
%n
: Ingenting förväntas. Antalet tecken som förbrukats så långt från inmatningen lagras genom nästa pekare, som måste vara en pekare till int. Detta är inte en konvertering och ökar inte antalet som returneras av funktionen.
Ovanstående kan användas tillsammans med numeriska modifierare och l
, L
-modifierarna som står för "lång" och "lång lång" mellan procentsymbolen och bokstaven. Det kan också finnas numeriska värden mellan procentsymbolen och bokstäverna, före de långa
modifierarna om några, som anger antalet tecken som ska skannas. En valfri asterisk ( *
) direkt efter procentsymbolen anger att datumet som läses av denna formatspecifikation inte ska lagras i en variabel. Inget argument bakom formatsträngen ska inkluderas för denna utelämnade variabel.
ff -
modifieraren i printf finns inte i scanf, vilket orsakar skillnader mellan in- och utmatningslägen. Modifierarna ll
och hh
finns inte i C90-standarden, men finns i C99-standarden.
Ett exempel på en formatsträng är
"%7d%s %c%lf"
Ovanstående formatsträng skannar de första sju tecknen som ett decimalt heltal, läser sedan de återstående som en sträng tills ett mellanslag, nyrad eller tabb hittas, förbrukar sedan blanksteg tills det första tecknet som inte är blanksteg hittas, förbrukar sedan det tecknet, och skannar slutligen de återstående tecknen som en dubbel . Därför måste ett robust program kontrollera om scanf
-anropet lyckades och vidta lämpliga åtgärder. Om ingången inte var i rätt format, kommer den felaktiga informationen fortfarande att finnas på ingångsströmmen och måste kasseras innan ny ingång kan läsas. En alternativ metod, som undviker detta, är att använda fgets
och sedan undersöka den inlästa strängen. Det sista steget kan göras med till exempel sscanf .
I fallet med de många float-tecknen a, e, f, g väljer många implementeringar att kollapsa mest i samma parser. Microsoft MSVCRT gör det med e, f, g , medan glibc gör det med alla fyra.
Sårbarheter
scanf
är sårbart för formatsträngsattacker . Stor försiktighet bör iakttas för att säkerställa att formateringssträngen inkluderar begränsningar för sträng- och matrisstorlekar. I de flesta fall är inmatningssträngens storlek från en användare godtycklig och kan inte fastställas innan scanf
-funktionen exekveras. Detta innebär att %s
platshållare utan längdspecifikationer är i sig osäkra och kan utnyttjas för buffertspill . Ett annat potentiellt problem är att tillåta dynamiska formateringssträngar, till exempel formateringssträngar lagrade i konfigurationsfiler eller andra användarkontrollerade filer. I det här fallet kan den tillåtna inmatningslängden för strängstorlekar inte specificeras om inte formateringssträngen kontrolleras i förväg och begränsningar tillämpas. Relaterade till detta är ytterligare eller felaktiga formateringsplatshållare som inte matchar den faktiska vararglistan . Dessa platshållare kan delvis extraheras från stacken eller innehålla oönskade eller till och med osäkra pekare, beroende på den specifika implementeringen av varargs .
Se även
externa länkar
- The Single UNIX Specification , Version 4 från The Open Group – System Interfaces Reference,
- C++ referens för
std::scanf