řetězec formátu scanf - scanf format string
Formát scanf string ( skenování f ormatted) je řídicí parametr používaný v různých funkcích k určení rozložení vstupního řetězce . Funkce pak mohou rozdělit řetězec a přeložit jej na hodnoty příslušných datových typů . Funkce skenování řetězců jsou často dodávány ve standardních knihovnách .
Termín „scanf“ pochází z knihovny C , která popularizovala tento typ funkcí, ale tyto funkce předcházejí C a používají se další názvy, například readf v ALGOL 68 . řetězce formátu scanf, které poskytují formátovaný vstup ( parsování ), doplňují řetězce formátu printf , které poskytují formátovaný výstup ( šablonování ). Poskytují jednoduchou funkčnost a pevný formát ve srovnání se sofistikovanějšími a flexibilnějšími analyzátory nebo šablonami, ale jsou dostatečné pro mnoho účelů.
Dějiny
Mike Lesk je přenosný vstup / výstup knihovna , včetně scanf oficiálně stala součástí Unix ve verzi 7 .
Používání
scanf Funkce, které lze nalézt v C , čte vstup pro čísla a dalších datových typů ze standardního vstupu (často rozhraní příkazové řádky nebo podobného druhu z uživatelského rozhraní textu ).
Následující kód C načte proměnný počet neformátovaných celých čísel v desítkovém formátu ze standardního vstupního proudu a vytiskne každý z nich na samostatné řádky:
#include <stdio.h>
int main(void)
{
int n;
while (scanf("%d", &n) == 1)
printf("%d\n", n);
return 0;
}
Po zpracování výše uvedeným programem se zobrazí nepravidelně rozložený seznam celých čísel, jako je
456 123 789 456 12
456 1
2378
se bude zobrazovat vždy jako:
456 123 789 456 12 456 1 2378
Tisk slova:
#include <stdio.h>
int main(void)
{
char word[20];
if (scanf("%19s", word) == 1)
puts(word);
return 0;
}
Bez ohledu na to, jaký datový typ programátor chce, aby program četl, argumenty (například &n výše) musí být ukazatele směřující do paměti. Jinak funkce nebude fungovat správně, protože se bude snažit přepsat nesprávné části paměti, místo aby ukazovala na paměťové místo proměnné, pro kterou se pokoušíte získat vstup.
V posledním příkladu adresa-operátora ( & se) není použit pro argument: jako word je jméno z pole o char , jako takové je (ve všech souvislostech, ve kterém se hodnotí na adresu), ekvivalentní ukazatel na první prvek pole. Zatímco výraz &word by se numericky vyhodnotil na stejnou hodnotu, sémanticky má zcela jiný význam v tom, že znamená adresu celého pole, nikoli jeho prvek. Tuto skutečnost je třeba mít na paměti při přiřazování scanf výstupu k řetězcům.
Jak scanf je určeno ke čtení pouze ze standardního vstupu, mnoho programovacích jazyků s rozhraními , jako je PHP , má deriváty jako sscanf a fscanf ne scanf samo o sobě.
Specifikace formátu řetězce
Formátování zástupné symboly ve scanf více či méně stejné jako v printf , jeho zadní funkce. Stejně jako v printf n$ je definováno rozšíření POSIX .
Ve formátovacím řetězci jsou zřídka konstanty (tj. Znaky, které nejsou formátovací zástupné symboly ), hlavně proto, že program obvykle není určen ke čtení známých dat, ačkoli scanf je výslovně specifikuje. Výjimkou je jeden nebo více prázdných znaků, které zahodí všechny prázdné znaky na vstupu.
Následují některé z nejčastěji používaných zástupných symbolů:
-
%a: Naskenuje číslo s plovoucí desetinnou čárkou v hexadecimálním zápisu. -
%d: Naskenuje celé číslo jako podepsané desetinné číslo. -
%i: Naskenuje celé číslo jako podepsané číslo. Podobné%d, ale interpretuje číslo jako šestnáctkové, když předchází,0xa osmičkové, když předchází0. Například řetězec031bude čten jako 31 pomocí%da 25 pomocí%i. Příznakhv%hioznačuje převod nashortahhpřevod na achar. -
%u: Skenovat na desetinná místaunsigned int(Všimněte si, že ve standardu C99 je znaménko mínus vstupní hodnoty volitelné, takže pokud je načteno znaménko mínus, nedojde k žádným chybám a výsledkem bude dvojkový doplněk záporného čísla, pravděpodobně velmi velká hodnota. vizstrtoul()). Odpovídajícím způsobem%huvyhledáváunsigned shorta%hhuu systémuunsigned char. -
%f: Skenování čísla s plovoucí desetinnou čárkou v normální notaci (s pevnou řádovou čárkou ). -
%g,%G: Naskenuje číslo s plovoucí desetinnou čárkou v normální nebo exponenciální notaci.%gpoužívá malá písmena a%Gvelká písmena. -
%x,%X: Naskenuje celé číslo jako šestnáctkové číslo bez znaménka . -
%o: Naskenuje celé číslo jako osmičkové číslo. -
%s: Naskenuje řetězec znaků . Skenování končí mezerami . Znak null je uložen na konci řetězce, což znamená, že dodaná vyrovnávací paměť musí být alespoň o jeden znak delší než zadaná délka vstupu. -
%c: Naskenuje znak (znak). Není přidán žádný prázdný znak . - prázdné znaky : Jakékoli prázdné znaky spustí skenování nulových nebo více prázdných znaků. Počet a typ prázdných znaků se nemusí shodovat v obou směrech.
-
%lf: Skenovat jako dvojité číslo s plovoucí desetinnou čárkou. Formát „Float“ se specifikátorem „long“. -
%Lf: Skenovat jako dlouhé dvojité číslo s plovoucí desetinnou čárkou. Formát „float“ specifikátor „long long“. -
%n: Nic se neočekává. Počet znaků spotřebovaných tak daleko od vstupu je uložen prostřednictvím dalšího ukazatele, který musí být ukazatelem na int. Nejedná se o převod a nezvyšuje počet vrácený funkcí.
Výše uvedené může být použit ve sloučenině s číselnými modifikátory a l , L modifikátory, které stojí za „dlouhé“ a „long“ mezi symbolem procent a písmeno. Mezi symbolem procenta a písmeny mohou být také číselné hodnoty, které předcházejí případné long modifikátory, které určují počet znaků, které mají být skenovány. Volitelná hvězdička ( * ) hned za symbolem procenta označuje, že datum přečtené tímto specifikátorem formátu nemá být uloženo v proměnné. U této zrušené proměnné by neměl být zahrnut žádný argument za formátovacím řetězcem.
ff Modifikátor v printf není přítomen v scanf, což způsobuje rozdíly mezi druhy vstupem a výstupem. ll A hh modifikátory nejsou přítomny ve standardu C90, ale jsou přítomny v normě C99.
Příkladem formátovacího řetězce je
"%7d%s %c%lf"
Řetězec výše uvedeného formátu skenuje prvních sedm znaků jako celé číslo v desítkové soustavě, potom čte zbývající jako řetězec, dokud nenajde mezeru, nový řádek nebo tabulátor, poté spotřebuje mezery, dokud není nalezen první znak, který není mezerou, a poté tento znak spotřebuje, a nakonec skenuje zbývající znaky jako dvojitý . Robustní program proto musí zkontrolovat, zda bylo scanf volání úspěšné, a provést příslušnou akci. Pokud vstup nebyl ve správném formátu, budou chybná data stále ve vstupním proudu a musí být zahozena, než bude možné číst nový vstup. Alternativní metodou, která se tomu vyhne, je použít fgets a poté zkontrolovat načtený řetězec. Poslední krok lze provést sscanf například.
V případě mnoha znaků typu float a, e, f, g se mnoho implementací rozhodlo sbalit nejvíce do stejného analyzátoru. Microsoft MSVCRT to dělá s e, f, g , zatímco glibc to dělá se všemi čtyřmi.
Zranitelnosti
scanf je zranitelný při formátování řetězcových útoků . Je třeba věnovat velkou pozornost tomu, aby formátovací řetězec obsahoval omezení velikostí řetězců a polí. Ve většině případů je velikost vstupního řetězce od uživatele libovolná a nelze ji určit před provedením scanf funkce. To znamená, že použití %s zástupných symbolů bez specifikátorů délky jsou inherentně nejistá a zneužitelná pro přetečení vyrovnávací paměti . Dalším potenciálním problémem je povolení řetězců dynamického formátování, například formátování řetězců uložených v konfiguračních souborech nebo jiných souborech ovládaných uživatelem. V tomto případě nelze zadat povolenou vstupní délku velikostí řetězce, pokud není předem zkontrolován formátovací řetězec a nejsou vynucena omezení. S tím souvisí další nebo neodpovídající zástupné symboly formátování, které neodpovídají skutečnému seznamu vararg . Tyto zástupné symboly mohou být částečně extrahovány ze zásobníku nebo obsahovat nežádoucí nebo dokonce nezabezpečené ukazatele, v závislosti na konkrétní implementaci varargs .
Viz také
Reference
externí odkazy
- - System Interfaces Reference, The Single UNIX Specification , Issue 7 from The Open Group
- C ++ reference pro
std::scanf