⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 retaggr.940616.html

📁 this is a mirrored site c-faq. thought might need offline
💻 HTML
字号:
<html><!-- Mirrored from c-faq.com/malloc/retaggr.940616.html by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 08:02:59 GMT --><head><title></title></head><body><p>[This test has been edited lightly since its original posting.]<p>Newsgroups: comp.lang.c<br>From: scs@eskimo.com (Steve Summit)<br>Subject: Re: Newbie: Should a function malloc or used fixed strings?<br>Message-ID: &lt;CrHu2G.D3B@eskimo.com&gt; [revised]<br>References: &lt;2tmtoi$1q4@hk.super.net&gt;<br>Date: Thu, 16 Jun 1994 14:11:01 GMT<p>In article &lt;2tmtoi$1q4@hk.super.net&gt;, Rodney Haywoodwrites:<br>&gt; I am writting a function that converts a number to a worded string, <br>&gt; normally used in a cheque print program. The length of the string<br>&gt; returned is not know until it is parsed by the function and could be<br>&gt; quite long 123 chars. I am not sure if it is best to pass a predefined<br>&gt; string to the function and have it place the result in it or to have<br>&gt; the function return a pointer to a sting that it allocated with <TT>malloc()</TT>.<br>&gt; <br>&gt; I can see pros and cons for the two. Using <TT>malloc</TT> gives more work to the<br>&gt; caller as they will need to <TT>free()</TT> the memory every time they are finished<br>&gt; with the current value of the string, otherwise if they called it 1000 <br>&gt; time it would continue to use memory that was no longer required. The <br>&gt; other way round the user could create a buffer to receive the string and<br>&gt; do the memory allocation themselves if they needed to keep it around. <br>&gt; If every thing is fixed lenght strings then there could be lots of wasted<br>&gt; space.<p>This is an excellent question, and you've already identified twoof the major tradeoffs.  Others have already mentioned others;I'll mention a few more that are important to me.<p>What I worry about most when designing a routine which mustreturn a string is the caller's convenience, especially if theroutine will be used a lot.  The questions to ask are:<ol><p><li>How much of a nuisance would it be for the caller topass in a buffer?<p><li>How much of a nuisance would it be for the caller to<TT>free()</TT> the returned pointers?<p><li>In what sorts of contexts will the call likely appear?<p><li>How likely is it that the caller will need to manipulateseveral returned strings simultaneously?</ol><p>Since the problem statement mentions a check printing program, wehave an example which nicely illustrates these tradeoffs.  If theroutine accepts a number like 1234.56 and returns a string like``One Thousand, Two Hundred and Thirty Four Dollars and Fifty Sixcents'', it is likely that the call to it will appear in a contextlike<p><pre>	extern char dollarformat();	printf("Pay to: %-40s  $%.2f\n", payee, amount);	printf("%-50s\n", dollarformat(amount));</pre><p>The above fragment sets the stage, and ignores <TT>dollarformat()</TT>'sreturn buffer allocation.  (It's also dollarocentric; apologies.)Let's look at how the call would appear using various allocationstrategies:<p>If the caller must pass in the buffer, we have (call this ``method A''):<p><pre>	char amountbuf[51];	printf("%-50s\n", dollarformat(amount, amountbuf, 51));</pre><p>If the routine returns a <TT>malloc</TT>'ed pointer, we have (``method B''):<p><pre>	char *amountret;	amountret = dollarformat(amount);	printf("%-50s\n", amountret);	free(amountret);</pre><p>or, if we don't mind some condensation,<p><pre>	printf("%-50s\n", amountret = dollarformat(amount));	free(amountret);</pre><p>Finally, if the routine returns the infamous ``pointer to a staticbuffer which is overwritten with each call,'' we can simply use(``method C''):<p><pre>	printf("%-50s\n", dollarformat(amount));</pre>(For this third technique, if you're not familiar with it,dollarformat's implementation looks something like<p><pre>	char *	dollarformat(double amount)	{	static char retbuf[RETBUFSIZE];	/* ... format amount into retbuf ... */	return retbuf;	}</pre><p>, where the static declaration of retbuf is vital, thoughsomewhat frequently overlooked.)<p>Functions which return pointers to static buffers (i.e. which usemethod C) have the annoying property that you can't call themtwice and keep using both return values, and this can be thesource of stubborn bugs.  For example, given the thirdimplementation, you can't do<p><pre>	char *p1 = dollarformat(amount1);	char *p2 = dollarformat(amount2);	printf("%s %s\n", p1, p2);</pre>or<pre>	printf("%s %s\n", dollarformat(amount1), dollarformat(amount2));</pre>However, if it is unlikely that the caller will want tomanipulate several values simultaneously, and if the caller won'tmind making explicit copies in those few instances when it does,static return values (method C) can be very convenient, becausethe caller never (well, hardly ever) has to worry about bufferallocation.  That's why the technique is popular in thetraditional C and Unix run-time libraries (e.g. <TT>ctime()</TT>,<TT>getpwuid()</TT>), although I'm sure this is one of the things thatdrives people who are less than fond of C and Unix up a tree.<p>Note that although static return buffers (method C) are usuallyused when the size of (or an upper bound on) the return buffer isknown, the function can also keep a single static pointer to anarea of dynamically-allocated memory which it grows (with<TT>realloc</TT>) as big as it needs to be for any single call.(It might use a second static variable to keep track of thebuffer's current size.)<p>If the caller wishes to manipulate several return valuessimultaneously and the function requires the caller to pass ina buffer (method A), the caller merely has to remember to passdistinct buffers:<p><pre>	char amountbuf1[51], amountbuf2[51];	printf("%s %s", dollarformat(amount1, amountbuf1, 51),			dollarformat(amount2, amountbuf2, 51));</pre>or<pre>	(void)dollarformat(amount1, amountbuf1, 51);	(void)dollarformat(amount2, amountbuf2, 51);	printf("%s %s", amountbuf1, amountbuf2);</pre><p>Note that when the caller passes in a buffer, it can either bestatically or dynamically allocated; the function doesn't care.<p>Note also that routines which accept caller-supplied buffers mustalways allow the size of that buffer to be specified, so that theroutine can guarantee not to overflow it.  Remember <TT>gets()</TT>vs. <TT>fgets()</TT>!<p>Finally, note that routines which return strings, in buffersprovided by their callers, are often described with words like``the routine returns its first argument'' (or, in this example,its second argument), which sounds silly at first glance (if thecaller knows it, why return it?), but which makes handing thestring to some other routine (in these examples, printf) veryeasy.<p>Finally, when the function returns a pointer to dynamicallyallocated memory (method B), it can be maximally easy for thecaller to manipulate multiple values simultaneously.  However, itcan be a real nuisance to keep a handle on the return value, inorder to free it.  Obvious invocations like<p><pre>	printf("%s\n", dollarprint(amount));</pre>are blatant (though not necessarily obvious) memory leaks.<p>Other people have mentioned efficiency, both of buffer space andallocation overhead.  In situations where strings are ofarbitrary length, fixed-length arrays are decidedly inferior:they're either too small and they overflow, or they're much toolarge and they waste space.<p>If an upper bound on the string's size can be determined and it'sa few hundred characters or less, though, using fixed-sizedarrays won't waste much (unless hundreds of arrays are allocatedsimultaneously), and their convenience is a distinct advantage.<p>To avoid the perils of fixed-size arrays, people who've beenaround for a while usually recommend dynamic allocation, althoughit must be admitted that the explicit management of allocationwhich this forces upon you, and the problems of memory leaks anddangling pointers (which were recently pointed out to beopposites -- nice observation, whoever it was!), can be quitedaunting; they probably represent the single biggest hurdle whenlearning C, and they account for a constant background level ofbugs, some of them so subtle they're never found, even in themost sophisticated programs written by the most sophisticatedprogrammers.<p>In most cases, though, <TT>malloc</TT>/<TT>free</TT> overhead is not a problem.(There are certainly exceptions, but that fact hardly impliesthat every program must eschew <TT>malloc</TT>, or write its own, or usefancy storage management wrappers.)<p>In the end, if the preceding discussion hasn't made it clear,there is no one best method of returning a string (or otheraggregate) from a function in C, nor is there a single ironcladreason always to prefer fixed-size or dynamically-allocatedarrays.  Usually you can find a good solution for any particularcase that comes up, but it's a good idea to think about it a bitto make sure you make a good choice.<p>The three return value methods above (A, B, and C) do not exhaustthe possibilities.  Some routines (<TT>getcwd</TT>, many GNU routines) usea combination of methods A and B, returning a pointer to<TT>malloc'ed</TT> memory if the caller passes a null pointer instead of abuffer.  People unclear on the concept occasionally try to returnstrings from functions to their callers via temporary files, butwe don't need to say much more about that approach.  Finally,there's a cunning extension on method C, which has evidently beenindependently discovered by a number of people, which returnspointers to static buffers and allows the caller to use up to N(but not N+1) return values simultaneously, but that's an articlefor another day.<p><address><a href="http://www.eskimo.com/~scs/">Steve Summit</a><br><a href="mailto:scs@eskimo.com">scs@eskimo.com</a></address></body><!-- Mirrored from c-faq.com/malloc/retaggr.940616.html by HTTrack Website Copier/3.x [XR&CO'2008], Sat, 14 Mar 2009 08:02:59 GMT --></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -