scanf vs scanf_s


svara 1:
  1. scanf er óskýr. Fáir sjá um að læra raunverulega scanf, enn færri kenna það reyndar. Skyndipróf: Vissir þú að það er nákvæmlega enginn munur á scanf (“\ n”); og scanf (“\ t”) ;? Veistu muninn á því að fá núll aftur og fá EOF til baka frá scanf? (og horfirðu jafnvel á hvað það skilar?). Breyta: og í 100. skipti er „% [^ \ n] s“ bull. Það sem er í því er tryggt bilun í samsvörun en samt heldur fólk að afrita það úr einni slæmri kennsluleiðbeining til annarrar.
  2. scanf er viðkvæmt fyrir villur Það er auðvelt að lemja óskilgreinda hegðun vegna villna eins og
  3. tegund misræmis (sem nútíma þýðendur greina, sem betur fer, með því að greina sniðstrenginn á samantektartíma): að lesa% f í int * er óskilgreint hegðun.
  4. Notkun% s - já,% s er villa, eins banvæn og notkun fyrri bókasafnsaðgerðarinnar fær (). Það verður alltaf að vera% Ns, þar sem N er stuðpóstastærð plús eitt. Sama gildir um% [.
  5. scanf er ósveigjanlegt. Það gerir á sama tíma of mikið - allt frá hvítum svigrúmi til að umbreyta Unicode - og of lítið. Það getur parað margt en er ekki nógu sveigjanlegt til að greina margar skynsamlegar málfræðirit. Það er takmarkað við 1 bleikjuhýði. Sérstillingarstaðir þess (staðbundnar hliðar) eru mjög takmarkaðir.
  6. scanf (eins og printf) er hægt. Sérhver skynsamur forritari getur skrifað hraðari þáttun vegna þess að það þyrfti ekki að para og túlka smámál á hlaupatíma og þyrfti ekki að gera allt það óskýra sem scanf gerir ..

Þrátt fyrir allt er það mjög þægilegt og virkar alveg ágætt þegar það er notað fyrir það sem það gerir vel, miðað við að þú vitir hvað þú ert að gera - en það er tilfellið fyrir alla hluti C!


svara 2:

Það fer eftir því hvernig það er notað. scanf () getur verið „skaðlegt eða slæmt“ ef einhver segir eitthvað svona:

bleikju * strengur1 = (bleikju *) malloc (8 * stærð af (bleikju) +1);scanf ("% s", strengur1);

Ofangreint er fínt * nema * ef stdin inntakstrengurinn er lengri en 8 stafir, ef í því tilfelli verður þú með yfirfall buffara.

Ég myndi leggja til að einn noti getline () í staðinn og noti síðan sscanf () til að para stafalausn úr getline (). Sjáðu td. :

bleikju * biðminni = NULL; stærð_t sz = 0; getline (& biðminni, & sz, stdin);int a, b, c;sscanf (biðminni, "% d% d% d", & a, & b, & c);...ókeypis (biðminni);

getline () með ofangreindum rökum * mun sjálfkrafa úthluta * biðminni nógu stórum til að geyma hvað sem notandinn tegundir eða hvað sem er lesið úr FILE bendlinum. Athugaðu að þú verður að losa þig við () úthlutaðan biðminni að lokum.

Jafnvel betra er að getline () er formlega hluti af C-staðalsafninu (** Sjá athugasemd hér að neðan), IIRC, sem er skilgreint í „stdio.h“. Upphaflega var það GNU GCC viðbót en var stöðluð sem hluti af POSIX.1-2008 sérstakri gerð (sjá:

Forskriftir Open Group Base Útgáfa 7, 2018 útgáfa

).

Vona að þetta hjálpi…

** ATH: Eins og bent er á í athugasemdum við þetta svar, er getline í raun * ekki * hluti af C staðalsafninu samkvæmt ANSI eða ISO C stöðlunum. En það * er * hluti af C staðalbókasafninu ef umrædd C útfærsla er í samræmi við POSIX sérstakan gagnvart þeim hluta POSIX sérstakan sem fjallar um C staðlaða bókasafnsaðgerðir og hausskrár, sem GCC og aðrir þýðendur gera.

EDIT # 1: Bara athugasemd, en ég mæli með að athuga aftur gildi getline () til að sjá hvort lok innsláttar hefur verið náð, td. :

ef (getline (& biðminni, & sz, stdin)! = -1) {...

Fyrir sscanf er einnig mælt með því að athuga skilagildið til að sjá hvort notandinn hafi slegið inn viðeigandi texta. Í ofangreindu dæmi gæti maður gert:

ef (sscanf (biðminni, "% d% d% d", & a, & b, & c) == 3) {...

EDIT # 1: Þakkir til Armand Klein fyrir að hafa lagt til breytingu sem leiðrétti prentvillu :)

EDIT # 2: Paul Olaru sagði að getline () sé ekki hluti af ANSI eða ISO C stöðlunum. Tæknilega séð er þetta rétt að getline () og getdelim () eru ekki hluti af ANSI eða ISO C stöðlunum. En þeir eru hluti af POSIX staðlinum, sem öll C-kerfin hafa ef POSIX er samhæft, sem inniheldur GCC og aðra C þýðendur. Eins og fyrir Microsoft VC, ̶ þótt MSVC Nennir, ̶ IIRC, ̶ innleiða öll þau POSIX staðlinum ̶w̶.̶r̶.̶t̶.̶ að C Standard bókasafn, ̶ það er, ̶ IIRC, ̶ innleiða mest af POSIX BASE C Standard LIBRARY aðgerðir [1]. Bent er á að I er hægt að rangt eins ég veit eða notkunar MSVC ̶: ̶) ̶

Til að sjá lista yfir hvaða hausar og venjulegar bókasafnsaðgerðir eru studdar af POSIX, skoðaðu hér: Fara til

Forskriftir Open Group Base Útgáfa 7, 2018 útgáfa

og farðu neðst til vinstri á síðunni og smelltu á „13. haus“. Næst skaltu smella á „ "og þú munt sjá að getline () og getdelim () eru þar.

Ég er ekki sammála því að flytjanlegur getline () aðgerð væri „bilaður“. Allt sem þarf að breyta væri meðhöndlun EOL afmarka og EOF / lok innsláttar. Ég myndi skrifa dæmi en það eru mörg dæmi á vefnum, td. þessi :

ivanrad / getline

.


svara 3:

Hver segir að það sé „slæm framkvæmd“? Það er gagnleg aðgerð. Fyrir löngu síðan var ekki um neina markaeftirlit að ræða, svo það gæti leitt til yfirfalls buffara. Svo langt sem ég veit að það gerist ekki í nútíma útfærslum á C og scanf () er ekki meira eða minna hættulegt en aðrar aðgerðir.

C er í öllu falli ekki tungumál fyrir forritara sem þarf að vernda gegn eigin vanhæfni. Þú verður að geta sinnt ábendingum á réttan hátt og úthlutað og sleppt eigin minni. Ólíkt mörgum nýrri tungumálum sem meðhöndla forritarann ​​sem einhvers konar ósegju sem þarf að koma í veg fyrir að gera eitthvað kjánalegt, gerir C fullan kraft vélarinnar fyrir þig en býst við að þú hafir kunnáttu og þekkingu til að vita hvað þú ert að gera , og til að gera það nákvæmlega. [Og auðvitað til að prófa rækilega]


svara 4:

Ég hef gert nokkrar rannsóknir og fundið ýmislegt áhugavert við forritara sem tengjast scanfs.

Hérna er tilfellið: gerðu ráð fyrir að þú viljir að notandinn gefi inn fjölda talna. Einnig er það hvernig forritið þitt virkar.

Skoðaðu þennan kóða:

# innifalið int aðal (ógilt){ int a; scanf ("% d", & a); ef (a == 1) { printf ("Þú slóst 1 \ n"); }Annar{ printf ("Þú slóst inn tölu \ n% d", a); } skila 0;}

Að vissu leyti myndi scanf ekki greina í þessari atburðarás ef notandi skrifaði staf, aukastaf eða raunverulegt heiltölu.

Þetta vandamál myndi verða mjög þýðingarmikið ef þú ert að reyna að kóða forrit sem eru mjög háð þessum tegundum flokkana.

En það þýðir ekki að nota scanfs sé slæmur venja. Það er mjög góð aðgerð til að nota. Eina vandamálið sem ég giska á væri að þú myndir eiga ansi erfitt með að kemba villu sem tengist scanfs, þar sem þó að þú hafir slegið bleikju á meðan forritið bað um heiltölu, þá myndi scanf einfaldlega beita þessu sem gildri keyrslu.

Ég vona að þetta svari spurningu þinni :)


svara 5:

Eins og margir hafa nefnt er scanf líklega ekki besta leiðin fyrir inntak notenda.

Persónulega uppáhald mitt fyrir inntak notenda er að nota fgets og skrifa innslátt notenda í bleikjufylkingu og síðan túlka fylkið.

Eða með öðrum orðum, meðhöndla öll inntak sem strengi og umbreyttu því að þínum þörfum (ef þú þarft heiltölu, notaðu atoi og atof til dæmis).

Lítum á þennan kóða, sem jafngildir scanf (“% d”, & var);

int var;bleikjainntak [10] = {0};fgets (inntak, 10, stdin);var = atoi (inntak);

Það er aðeins flóknara en miklu, miklu öruggara. fgets les þar til það er þrotið á biðminni eða finnur '\ n' staf. Það mun innihalda þann '\ n' staf í strengnum líka, svo ef þú vilt geyma strengi, vertu viss um að fjarlægja það.

Samt eru þessi vandræði léttvæg til að laga samanborið við allt stdin roði sem þú þarft að gera við scanf, og þú verður varinn fyrir buffer umframmagn.


svara 6:

„Af hverju er scanf () í C talið skaðlegt eða slæmt?“

Það er munur á C tungumálinu og C staðalsafninu. Hið venjulega bókasafn er fullkomlega valfrjálst. Þú þarft ekki að nota aðgerðirnar bara af því að þær eru til staðar.

Scanf () er líklega ekki bestu gæði. Printf () fjölskyldan af aðgerðum er ótrúlegur árangur og það er rökrétt skref að búa til svipaða aðgerð fyrir sniðinntak. En ég tel að það hafi ekki gengið mjög vel.

Scanf () virkar, en það er erfitt að gera heimskan og öruggan. Það er hægt og hefur stórt minnis fótspor. Ég notaði scanf () aldrei í forritunum mínum og þurfti að skipta um það með sérsniðnum þáttum í erlendum kóða.