📄 faqcat1d60.html
字号:
<hr><hr><hr><a name="printfvwid"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/printfvwid.html"><!-- qtag -->Question 12.10</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I implement a variable field width with <TT>printf</TT>?That is, instead ofsomething like<TT>%8d</TT>,I want the width to be specifiedat run time.</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font><TT>printf("%*d", width, x)</TT>will do just what you want.The asteriskin the format specifierindicates thatan<TT>int</TT> value from the argument listwill be used for thefieldwidth.(Note thatinthe argument list,the widthprecedesthe value to be printed.)See also question <a href="faqcat1d60.html?sec=stdio#scanfvwid">12.15</a>.</p><p>References:K&R1 Sec. 7.3<br>K&R2 Sec. 7.2<br>ISO Sec. 7.9.6.1<br>H&S Sec. 15.11.6<br>CT&P Sec. A.1<hr><hr><hr><a name="commaprint"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/commaprint.html"><!-- qtag -->Question 12.11</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I print numbers with commas separating the thousands?<br>What about currency formatted numbers?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>The functions in <TT><locale.h></TT>begin to provide some supportfor these operations,butthereis no standard C functionfor doing eithertask.(In Standard C, the only thing <TT>printf</TT> doesin response to a custom locale settingis to change itsdecimal-point character.)</p><p>POSIX specifies a <TT>strfmon</TT> function for formatting monetary quantitiesin a locale-appropriate way,and that the apostrophe flag in a numeric <TT>printf</TT> format specifier(e.g. <TT>%'d</TT>, <TT>%'f</TT>)requests comma-separated digits.</p><p>Here is a little routine for formatting comma-separated numbers,using the locale's thousands separator, if available:<pre>#include <locale.h>char *commaprint(unsigned long n){ static int comma = '\0'; static char retbuf[30]; char *p = &retbuf[sizeof(retbuf)-1]; int i = 0; if(comma == '\0') { struct lconv *lcp = localeconv(); if(lcp != NULL) { if(lcp->thousands_sep != NULL && *lcp->thousands_sep != '\0') comma = *lcp->thousands_sep; else comma = ','; } } *p = '\0'; do { if(i%3 == 0 && i != 0) *--p = comma; *--p = '0' + n % 10; n /= 10; i++; } while(n != 0); return p;}</pre>(A better implementation would usethe <TT>grouping</TT> field ofthe <TT>lconv</TT> structure,rather than assuming groups of three digits.A safer size for <TT>retbuf</TT> might be<TT>4*(sizeof(long)*CHAR_BIT+2)/3/3+1</TT>;see question <a href="faqcat1d60.html?sec=stdio#sprintfsize">12.21</a>.)</p><p>References:ISO Sec. 7.4<br>H&S Sec. 11.6 pp. 301-4<hr><hr><hr><a name="scanf1"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/scanf1.html"><!-- qtag -->Question 12.12</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>Why doesn't the call<TT>scanf("%d", i)</TT>work?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>Thearguments youpass to <TT>scanf</TT>must always bepointers:for each value converted,<TT>scanf</TT> ``returns'' itby filling in one of the locationsyou've passed pointers to.(See also question <a href="faqcat38c2.html?sec=misc#multretval">20.1</a>.)To fixthe fragment above,change it to<TT>scanf("%d", &i)</TT>.<hr><hr><hr><a name="scanf1a"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/scanf1a.html"><!-- qtag -->Question 12.12b</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>Why <em>does</em> the call<pre>char s[30];scanf("%s", s);</pre>work?I thought you always needed an <TT>&</TT>on each variable passed to <TT>scanf</TT>.</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>You always need a <em>pointer</em>;you don't necessarily need an explicit <TT>&</TT>.When you pass an array to <TT>scanf</TT>,you do not needthe <TT>&</TT>,becausearraysarealwayspassed to functions as pointers,whether you use <TT>&</TT> or not.See questions <a href="faqcatca65.html?sec=aryptr#aryptrequiv">6.3</a>and <a href="faqcatca65.html?sec=aryptr#aryptrparam">6.4</a>.(If you did use an explicit <TT>&</TT>,you'd get the wrong type of pointer;see question <a href="faqcatca65.html?sec=aryptr#aryvsadr">6.12</a>.)<hr><hr><hr><a name="scanf2"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/scanf2.html"><!-- qtag -->Question 12.13</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>Why doesn'tthis code:<pre>double d;scanf("%f", &d);</pre>work?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>Unlike<TT>printf</TT>,<TT>scanf</TT> uses <TT>%lf</TT> forvalues of type<TT>double</TT>, and <TT>%f</TT> for <TT>float</TT>.<a href="../../stdio/fpfmts2.html" rel=subdocument>[footnote]</a><TT>%f</TT> tells <TT>scanf</TT> to expect a pointer-to-<TT>float</TT>,not the pointer-to-<TT>double</TT> you gave it.Either use <TT>%lf</TT>,ordeclare thereceivingvariable as a <TT>float</TT>.See also question <a href="faqcat1d60.html?sec=stdio#scanfvsprintf">12.9</a>.<hr><hr><hr><a name="scanfh"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/scanfh.html"><!-- qtag -->Question 12.14</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>Why doesn't the code<pre>short int s;scanf("%d", &s);</pre>work?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>When converting <TT>%d</TT>,<TT>scanf</TT> expects a pointer to an <TT>int</TT>.To convert to a <TT>short int</TT>, use <TT>%hd</TT>.(See also the table in question <a href="faqcat1d60.html?sec=stdio#scanfvsprintf">12.9</a>.)<hr><hr><hr><a name="scanfvwid"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/scanfvwid.html"><!-- qtag -->Question 12.15</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I specify a variable width in a <TT>scanf</TT> format string?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>You can't;an asteriskin a <TT>scanf</TT>format stringmeans to suppress assignment.Youmay be able touse ANSIstringizing andstring concatenationto construct a constant format specifierbased on a preprocessor macro containing the desired width:<pre>#define WIDTH 3#define Str(x) #x#define Xstr(x) Str(x) /* see question <a href="faqcat7d4b.html?sec=ansi#stringize">11.17</a> */scanf("%" Xstr(WIDTH) "d", &n);</pre>If the width is a run-time variable,though,you'll have tobuild the format specifier at run time, too:<pre>char fmt[10];sprintf(fmt, "%%%dd", width);scanf(fmt, &n);</pre>(<TT>scanf</TT> formats like theseare unlikely when reading from standard input,but might find some usefulnesswith <TT>fscanf</TT> or <TT>sscanf</TT>.)</p><p>See also questions <a href="faqcat7d4b.html?sec=ansi#stringize">11.17</a> and <a href="faqcat1d60.html?sec=stdio#printfvwid">12.10</a>.<hr><hr><hr><a name="datafmts"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/datafmts.html"><!-- qtag -->Question 12.16</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>How can I read data fromdata files with particular formats?<br>How can I read ten floats without having to use a jawbreaker <TT>scanf</TT> format<br>like<TT>"%f %f %f %f %f %f %f %f %f %f"</TT>?<br>How can I read an arbitrary number of fields from a line into an array?</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>In general, there are threemain waysof parsing data lines:</p><OL><li>Use<TT>fscanf</TT> or <TT>sscanf</TT>,withan appropriate format string.Despite the limitationsmentioned in this section(see question <a href="faqcat1d60.html?sec=stdio#scanfprobs">12.20</a>),the <TT>scanf</TT> family is quite powerful.Though whitespace-separated fields are always the easiest to deal with,<TT>scanf</TT> format strings can also be usedwith more compact,column oriented, FORTRAN-style data.For instance, the line<pre> 1234ABC5.678</pre>could bereadwith <TT>"%d%3s%f"</TT>.(See also the last example in question <a href="faqcat1d60.html?sec=stdio#scanfjam">12.19</a>.)<li>Break the line intofields separated bywhitespace(or some other delimiter),using <TT>strtok</TT> or the equivalent(see question <a href="faqcat1067.html?sec=lib#strtok">13.6</a>),then deal with each field individually,perhaps with functions like <TT>atoi</TT>and <TT>atof</TT>.(Once the line is broken up,the code for handling the fieldsis much like the traditional code in <TT>main()</TT>for handling the <TT>argv</TT> array;see question <a href="faqcat38c2.html?sec=misc#argv">20.3</a>.)This method is particularly usefulfor reading an arbitrary(i.e. not known in advance)numberof fields from a line into an array.<p>Here is a simple examplewhich copies a line ofup to 10floating-point numbers(separated by whitespace)into an array:<pre>#define MAXARGS 10char line[] = "1 2.3 4.5e6 789e10";char *av[MAXARGS];int ac, i;double array[MAXARGS];ac = makeargv(line, av, MAXARGS);for(i = 0; i < ac; i++) array[i] = atof(av[i]);</pre>(See question <a href="faqcat1067.html?sec=lib#strtok">13.6</a>for the definition of <TT>makeargv</TT>.)</p><li>Use whatever pointer manipulationsand library routinesare handyto parse the line in anad-hoc way.(The ANSI <TT>strtol</TT> and <TT>strtod</TT> functionsare particularly useful for this style of parsing,because they can return a pointerindicating where they stopped reading.)Thisis obviously the most general way,but it's also the most difficult and error-prone:thethorniestpartsofmanyC programsarethose which use lots oftrickylittle pointers to pick apart strings.</OL><p>Whenpossible, design data files and input formatsso that they don't require arcane manipulations,butcaninsteadbe parsed with easier techniquessuch as 1 and 2:dealing with the files willthenbemuch more pleasantall around.<hr><hr><hr><a name="scanfhang"><h1>comp.lang.c FAQ list<font color=blue>·</font><a href="../../stdio/scanfhang.html"><!-- qtag -->Question 12.17</a></h1><p><font face=Helvetica size=8 color=blue><b>Q:</b></font>When I readnumbersfrom the keyboard with<TT>scanf</TT>and a<TT>"%d\n"</TT>format,like this:<pre> int n; scanf("%d\n", &n); printf("you typed %d\n", n);</pre>it seems to hang until I type one extra line of input.</p><p><hr><p><font face=Helvetica size=8 color=blue><b>A:</b></font>Perhaps surprisingly,<TT>\n</TT>in a<TT>scanf</TT>format stringdoes<em>not</em>meanto expect a newline,but ratherto read and discard charactersas long as each is a whitespace character.(In fact,any whitespace character in a <TT>scanf</TT> format stringmeans to read and discard whitespace characters.<a href="../../stdio/krerr.html" rel=subdocument>[footnote]</a>Furthermore, formats like <TT>%d</TT> also discard leading whitespace,so you usually don't needexplicitwhitespace in <TT>scanf</TT> format stringsat all.)</p><p>The <TT>\n</TT> in <TT>"%d\n"</TT>thereforecauses <TT>scanf</TT> to read charactersuntil it finds a non-whitespace character,and it may need to read another linebefore it can find that non-whitespace character.In this case, the fix is just to use <TT>"%d"</TT>,without the <TT>\n</TT>(athoughyour program maythenneed to skip over the unread newline;see question <a href="faqcat1d60.html?sec=stdio#scanfinterlace">12.18a</a>).</p><p><TT>scanf</TT> was designed for free-format input,which is seldom what you want when reading from the keyboard.By ``free format''we mean that <TT>scanf</TT> does not treat newlines differentlyfromother whitespace.The format <TT>"%d %d %d"</TT>would be equally happyreading the input<pre> 1 2 3</pre>or<pre> 1 2 3</pre></p><p>(By way of comparison,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -