7. Memory Allocation

comp.lang.c FAQ list · Question 7.1

Q: Why doesn't this fragment work?

	char *answer;
	printf("Type something:\n");
	gets(answer);
	printf("You typed \"%s\"\n", answer);


A: The pointer variable answer, which is handed to gets() as the location into which the response should be stored, has not been set to point to any valid storage. It is an uninitialized variable, just as is the variable i in

	int i;
	printf("i = %d\n", i);
That is, in the first piece of code, we cannot say where the pointer answer points, just as we cannot say what value i will have in the second. (Since local variables are not initialized, and typically contain garbage, it is not even guaranteed that answer starts out as a null pointer. See questions 1.30 and 5.1.)

The simplest way to correct the question-asking program is to use a local array, instead of a pointer, and let the compiler worry about allocation:

#include <stdio.h>
#include <string.h>

char answer[100], *p;
printf("Type something:\n");
fgets(answer, sizeof answer, stdin);
if((p = strchr(answer, '\n')) != NULL)
	*p = '\0';
printf("You typed \"%s\"\n", answer);

This example also uses fgets() instead of gets(), so that the end of the array cannot be overwritten. (See question 12.23. Unfortunately for this example, fgets() does not automatically delete the trailing \n, as gets() would.) It would also be possible to use malloc() to allocate the answer buffer, and to parameterize the buffer size (with something like #define ANSWERSIZE 100 ).


comp.lang.c FAQ list · Question 7.2

Q: I can't get strcat to work. I tried

	char *s1 = "Hello, ";
	char *s2 = "world!";
	char *s3 = strcat(s1, s2);
but I got strange results.


A: As in question 7.1, the main problem here is that space for the concatenated result is not properly allocated. C does not provide an automatically-managed string type. C compilers allocate memory only for objects explicitly mentioned in the source code (in the case of strings, this includes character arrays and string literals). The programmer must arrange for sufficient space for the results of run-time operations such as string concatenation, typically by declaring arrays, or by calling malloc.

strcat performs no allocation; the second string is appended to the first one, in place. The first (destination) string must be writable and have enough room for the concatenated result. Therefore, one fix would be to declare the first string as an array:

	char s1[20] = "Hello, ";
(In production code, of course, we wouldn't use magic numbers like ``20''; we'd use more robust mechanisms to guarantee sufficient space.)

Since strcat returns the value of its first argument (s1, in this case), the variable s3 in the question above is superfluous; after the call to strcat, s1 contains the result.

The original call to strcat in the question actually has two problems: the string literal pointed to by s1, besides not being big enough for any concatenated text, is not necessarily writable at all. See question 1.32.

References: CT&P Sec. 3.2 p. 32




comp.lang.c FAQ list · Question 7.3

Q: But the man page for strcat says that it takes two char *'s as arguments. How am I supposed to know to allocate things?


A: In general, when using pointers you always have to consider memory allocation, if only to make sure that the compiler is doing it for you. If a library function's documentation does not explicitly mention allocation, it is usually the caller's problem.

The Synopsis section at the top of a Unix-style man page or in the ANSI C standard can be misleading. The code fragments presented there are closer to the function definitions used by an implementor than the invocations used by the caller. In particular, many functions which accept pointers (e.g. to structures or strings) are usually called with a pointer to some object (a structure, or an array--see questions 6.3 and 6.4) which the caller has allocated. Other common examples are time (see question 13.12) and stat.




comp.lang.c FAQ list · Question 7.3b

Q: I just tried the code

char *p;
strcpy(p, "abc");
and it worked. How? Why didn't it crash?


A: You got lucky, I guess. The memory randomly pointed to by the uninitialized pointer p happened to be writable by you, and apparently was not already in use for anything vital. See also question 11.35.

Additional links: longer explanation, another longer explanation




comp.lang.c FAQ list · Question 7.3c

Q: How much memory does a pointer variable allocate?


A: That's a pretty misleading question. When you declare a pointer variable, as in

	char *p;
you (or, more properly, the compiler) have allocated only enough memory to hold the pointer itself; that is, in this case you have allocated sizeof(char *) bytes of memory. But you have not yet allocated any memory for the pointer to point to. See also questions 7.1 and 7.2.


comp.lang.c FAQ list · Question 7.4

Q: I'm reading lines from a file into an array, with this code:

	char linebuf[80];
	char *lines[100];
	int i;

	for(i = 0; i < 100; i++) {
		char *p = fgets(linebuf, 80, fp);
		if(p == NULL) break;
		lines[i] = p;
	}
Why do all the lines end up containing copies of the last line?


A: You have only allocated memory for one line, linebuf. Each time you call fgets, the previous line is overwritten. fgets doesn't do any memory allocation: unless it reaches EOF (or encounters an error), the pointer it returns is the same pointer you handed it as its first argument (in this case, a pointer to your single linebuf array).

To make code like this work, you'll need to allocate memory for each line. See question 20.2 for an example.

References: K&R1 Sec. 7.8 p. 155
K&R2 Sec. 7.7 pp. 164-5
ISO Sec. 7.9.7.2
H&S Sec. 15.7 p. 356




comp.lang.c FAQ list · Question 7.5a

Q: I have a function that is supposed to return a string, but when it returns to its caller, the returned string is garbage.


A: Whenever a function returns a pointer, make sure that the pointed-to memory is properly allocated. For example, make sure you have not done something like


#include <stdio.h>
char *itoa(int n) { char retbuf[20]; /* WRONG */ sprintf(retbuf, "%d", n); return retbuf; /* WRONG */ }
When a function returns, its automatic, local variables are discarded, so the returned pointer in this case is invalid (it points to an array that no longer exists).

One fix would be to declare the return buffer as

		static char retbuf[20];
This fix is imperfect, since a function using static data is not reentrant. Furthermore, successive calls to this version of itoa keep overwriting the same return buffer: the caller won't be able to call it several times and keep all the return values around simultaneously.

See also questions 7.5b, 12.21, and 20.1.

References: ISO Sec. 6.1.2.4




comp.lang.c FAQ list · Question 7.5b

Q: So what's the right way to return a string or other aggregate?


A: The returned pointer should be to a statically-allocated buffer (as in the answer to question 7.5a), or to a buffer passed in by the caller, or to memory obtained with malloc, but not to a local (automatic) array.

For example, to have the caller pass space for the result:

	char *itoa(int n, char *retbuf)
	{
		sprintf(retbuf, "%d", n);
		return retbuf;
	}

	...

	char str[20];
	itoa(123, str);

To use malloc:

	#include <stdlib.h>

	char *itoa(int n)
	{
		char *retbuf = malloc(20);
		if(retbuf != NULL)
			sprintf(retbuf, "%d", n);
		return retbuf;
	}

	...

	char *str = itoa(123);
(In this last case, the caller must remember to free the returned pointer when it is no longer needed.)

See also question 20.1.

Additional links: further reading




comp.lang.c FAQ list · Question 7.6

Q: Why am I getting ``warning: assignment of pointer from integer lacks a cast'' for calls to malloc?


A: Have you #included <stdlib.h>, or otherwise arranged for malloc to be declared properly? If not, the compiler assumes that it returns an int (see question 1.25), which is not correct. (The same problem could arise for calloc or realloc.) See also question 7.15.

References: H&S Sec. 4.7 p. 101




comp.lang.c FAQ list · Question 7.7

Q: Why does some code carefully cast the values returned by malloc to the pointer type being allocated?


A: Before ANSI/ISO Standard C introduced the void * generic pointer type, these casts were typically required to silence warnings (and perhaps induce conversions) when assigning between incompatible pointer types.

Under ANSI/ISO Standard C, these casts are no longer necessary. It can also be argued that they are now to be discouraged; see question 7.7b. Furthermore, well-defined, low-risk implicit conversions (such as those which C has always performed between integer and floating-point types) can be considered a feature.

On the other hand, some programmers prefer to make every conversion explicit, to record that they have considered each case and decided exactly what should happen (see also question 17.5). Also, the casts are typically seen in C code which for one reason or another is intended to be compatible with C++, where explicit casts from void * are required.

(By the way, the language in sections 6.5 and 7.8.5 of K&R2 which suggests that the casts are required is ``overenthusiastic.'')

To some extent, whether you use these casts or not is a matter of style; see section 17.

Additional links: further explanation by Mark Brader

References: H&S Sec. 16.1 pp. 386-7




comp.lang.c FAQ list · Question 7.7b

Q: What's wrong with casting malloc's return value?


A: Suppose that you call malloc but forget to #include <stdlib.h>. The compiler is likely to assume that malloc is a function returning int, which is of course incorrect, and will lead to trouble. Now, if your call to malloc is of the form

	char *p = malloc(10);
the compiler will notice that you're seemingly assigning an integer to a pointer, and will likely emit a warning of the form ``assignment of pointer from integer lacks a cast'' (see question 7.6), which will alert you to the problem. (The problem is of course that you forgot to #include <stdlib.h>, not that you forgot to use a cast.) If, on the other hand, your call to malloc includes a cast:
	char *p = (char *)malloc(10);
the compiler is likely to assume that you know what you're doing, that you really do want to convert the int returned by malloc to a pointer, and the compiler therefore probably won't warn you. But of course malloc does not return an int, so trying to convert the int that it doesn't return to a pointer is likely to lead to a different kind of trouble, which will be harder to track down.

(Of course, compilers are increasingly likely--especially under C99--to emit warnings whenever functions are called without prototypes in scope, and such a warning would alert you to the lack of <stdlib.h> whether casts were used or not.)




comp.lang.c FAQ list · Question 7.7c

Q: In a call to malloc, what does an error like ``Cannot convert `void *' to `int *''' mean?


A: It means you're using a C++ compiler instead of a C compiler. See question 7.7.




comp.lang.c FAQ list · Question 7.8

Q: I see code like

	char *p = malloc(strlen(s) + 1);
	strcpy(p, s);
Shouldn't that be malloc((strlen(s) + 1) * sizeof(char))?


A: It's never necessary to multiply by sizeof(char), since sizeof(char) is, by definition, exactly 1. (On the other hand, multiplying by sizeof(char) doesn't hurt, and in some circumstances may help by introducing a size_t into the expression; see question 7.15.) See also questions 8.9 and 8.10.

References: ISO Sec. 6.3.3.4
H&S Sec. 7.5.2 p. 195




comp.lang.c FAQ list · Question 7.9

Q: I wrote a little wrapper around malloc, but it doesn't work:

	#include <stdio.h>
	#include <stdlib.h>

	mymalloc(void *retp, size_t size)
	{
		retp = malloc(size);
		if(retp == NULL) {
			fprintf(stderr, "out of memory\n");
			exit(EXIT_FAILURE);
		}
	}


A: See question 4.8. (In this case, you'll want to have mymalloc return the malloc'ed pointer.)




comp.lang.c FAQ list · Question 7.10

Q: I'm trying to declare a pointer and allocate some space for it, but it's not working. What's wrong with this code?

char *p;
*p = malloc(10);


A: See question 4.2.




comp.lang.c FAQ list · Question 7.10a

Q: What's wrong with this initialization?

char *p = malloc(10);
My compiler is complaining about an ``invalid initializer'', or something.


A: See question 1.31b.




comp.lang.c FAQ list · Question 7.10b

Q: How can I shut off the ``warning: possible pointer alignment problem'' message which lint gives me for each call to malloc?


A: See question 18.5.




comp.lang.c FAQ list · Question 7.11

Q: How can I dynamically allocate arrays?


A: See questions 6.14 and 6.16.




comp.lang.c FAQ list · Question 7.12

Q: How can I find out how much memory is available?


A: See question 19.22.




comp.lang.c FAQ list · Question 7.13

Q: What should malloc(0) do? Return a null pointer or a pointer to 0 bytes?


A: See question 11.26.




comp.lang.c FAQ list · Question 7.14

Q: I've heard that some operating systems don't actually allocate malloc'ed memory until the program tries to use it. Is this legal?


A: It's hard to say. The Standard doesn't say that systems can act this way, but it doesn't explicitly say that they can't, either. (Such a ``deferred failure'' implementation would not seem to conform to the implied requirements of the Standard.)

The conspicuous problem is that, by the time the program gets around to trying to use the memory, there might not be any. The program in this case must typically be killed by the operating system, since the semantics of C provide no recourse. (Obviously, malloc is supposed to return a null pointer if there's no memory, so that the program--as long as it checks malloc's return value at all--never tries to use more memory than is available.)

Systems that do this ``lazy allocation'' usually provide extra signals indicating that memory is dangerously low, but portable or naïve programs won't catch them. Some systems that do lazy allocation also provide a way to turn it off (reverting to traditional malloc semantics), on a per-process or per-user basis, but the details vary from system to system.

Additional links: A longer explanation of the tradeoffs concerning ``lazy allocation''

References: ISO Sec. 7.10.3




comp.lang.c FAQ list · Question 7.15

Q: malloc is returning crazy pointer values, but I did read question 7.6 and I have included the line

	extern void *malloc();
before I call it.


A: malloc accepts an argument of type size_t, and size_t may be defined as unsigned long. If you are passing ints (or even unsigned ints), malloc may be receiving garbage (or similarly if you are passing a long but size_t is int).

In general, it is much, much safer to declare standard library functions by #including the appropriate header files, rather than typing extern declarations yourself. See also question 7.16.

(A related problem is that it is not safe to print size_t values, including the result of sizeof, using printf's %d format. The portable approach is to use an explicit (unsigned long) cast, and %lu format: printf("%lu\n", (unsigned long)sizeof(int)). See also question 15.3.)

References: ISO Sec. 7.1.6, Sec. 7.1.7




comp.lang.c FAQ list · Question 7.16

Q: I'm allocating a large array for some numeric work, using the line

	double *array = malloc(300 * 300 * sizeof(double));
malloc isn't returning null, but the program is acting strangely, as if it's overwriting memory, or malloc isn't allocating as much as I asked for, or something.


A: Notice that 300 x 300 is 90,000, which will not fit in a 16-bit int, even before you multiply it by sizeof(double). If you need to allocate this much memory, you'll have to be careful. If size_t (the type accepted by malloc) is a 32-bit type on your machine, but int is 16 bits, you might be able to get away with writing 300 * (300 * sizeof(double)) (see question 3.14). Otherwise, you'll have to break your data structure up into smaller chunks, or use a 32-bit machine or compiler, or use some nonstandard memory allocation functions. See also questions 7.15 and 19.23.




comp.lang.c FAQ list · Question 7.17

Q: I've got 8 meg of memory in my PC. Why can I only seem to malloc 640K or so?


A: Under the segmented architecture of PC compatibles, it can be difficult to use more than 640K with any degree of transparency, especially under MS-DOS. See also question 19.23.




comp.lang.c FAQ list · Question 7.18

Q: My application depends heavily on dynamic allocation of nodes for data structures, and malloc/free overhead is becoming a bottleneck. What can I do?


A: One improvement, which is particularly attractive if all nodes are the same size, is to place unused nodes on your own free list, rather than actually freeing them. (This approach works well when one kind of data structure dominates a program's memory use, but it can cause as many problems as it solves if so much memory is tied up in the list of unused nodes that it isn't available for other purposes.)




comp.lang.c FAQ list · Question 7.19

Q: My program is crashing, apparently somewhere down inside malloc, but I can't see anything wrong with it. Is there a bug in malloc?


A: It is unfortunately very easy to corrupt malloc's internal data structures, and the resulting problems can be stubborn. The most common source of problems is writing more to a malloc'ed region than it was allocated to hold; a particularly common bug is to malloc(strlen(s)) instead of strlen(s) + 1. [footnote] Other problems may involve using pointers to memory that has been freed, freeing pointers twice, freeing pointers not obtained from malloc, freeing null pointers, allocating 0-sized objects (see question 11.26), or trying to realloc a null pointer (see question 7.30). (The last three--freeing null pointers, allocating 0-sized objects, and reallocing a null pointer--are sanctioned by the Standard, though older implementations often have problems.) Consequences of any of these errors can show up long after the actual mistake and in unrelated sections of code, making diagnosis of the problem quite difficult.

Most implementations of malloc are particularly vulnerable to these problems because they store crucial pieces of internal information directly adjacent to the blocks of memory they return, making them easy prey for stray user pointers.

See also questions 7.15, 7.26, 16.8, and 18.2.




comp.lang.c FAQ list · Question 7.19b

Q: I'm dynamically allocating an array, like this:

	int *iarray = (int *)malloc(nints);
malloc isn't returning NULL, but the code isn't working.


A: malloc is a low-level, typeless allocator. It doesn't know how you're going to use the memory; all it does is to allocate as many bytes of memory as you ask it. Therefore (except when you're allocating arrays of char) you must multiply by the size of the elements in the array you're allocating:

	int *iarray = malloc(nints * sizeof(int));
or
	int *iarray = malloc(nints * sizeof(*iarray));
(The latter fragment can be more reliable if the type of iarray might change, since there's only one place to change it. Also, the casts have been removed; see question 7.7.) Compare question 4.4, and see also question 7.8.


comp.lang.c FAQ list · Question 7.20

Q: You can't use dynamically-allocated memory after you free it, can you?


A: No. Some early documentation for malloc stated that the contents of freed memory were ``left undisturbed,'' but this ill-advised guarantee was never universal and is not required by the C Standard.

Few programmers would use the contents of freed memory deliberately, but it is easy to do so accidentally. Consider the following (correct) code for freeing a singly-linked list:

	struct list *listp, *nextp;
	for(listp = base; listp != NULL; listp = nextp) {
		nextp = listp->next;
		free(listp);
	}
and notice what would happen if the more-obvious loop iteration expression listp = listp->next were used, without the temporary nextp pointer.

References: K&R2 Sec. 7.8.5 p. 167
ISO Sec. 7.10.3
Rationale Sec. 4.10.3.2
H&S Sec. 16.2 p. 387
CT&P Sec. 7.10 p. 95




comp.lang.c FAQ list · Question 7.21

Q: Why isn't a pointer null after calling free?
How unsafe is it to use (assign, compare) a pointer value after it's been freed?


A: When you call free, the memory pointed to by the passed pointer is freed, but the value of the pointer in the caller probably remains unchanged, because C's pass-by-value semantics mean that called functions never permanently change the values of their arguments. (See also question 4.8.)

A pointer value which has been freed is, strictly speaking, invalid, and any use of it, even if it is not dereferenced (i.e. even if the use of it is a seemingly innocuous assignment or comparison), can theoretically lead to trouble. (We can probably assume that as a quality of implementation issue, most implementations will not go out of their way to generate exceptions for innocuous uses of invalid pointers, but the Standard is clear in saying that nothing is guaranteed, and there are system architectures for which such exceptions would be quite natural.)

When pointer variables (or fields within structures) are repeatedly allocated and freed within a program, it is often useful to set them to NULL immediately after freeing them, to explicitly record their state.

References: ISO Sec. 7.10.3
Rationale Sec. 3.2.2.3




comp.lang.c FAQ list · Question 7.22

Q: When I call malloc to allocate memory for a pointer which is local to a function, do I have to explicitly free it?


A: Yes. Remember that a pointer is different from what it points to. Local variables [footnote] are deallocated when the function returns, but in the case of a pointer variable, this means that the pointer is deallocated, not what it points to. Memory allocated with malloc always persists until you explicitly free it. (If the only pointer to a block of malloc'ed memory is a local pointer, and if that pointer disappears, there will be no way to free that block.) In general, for every call to malloc, there should be a corresponding call to free.




comp.lang.c FAQ list · Question 7.23

Q: I'm allocating structures which contain pointers to other dynamically-allocated objects. When I free a structure, do I also have to free each subsidiary pointer?


A: Yes. malloc knows nothing about structure declarations or about the contents of allocated memory; it especially does not know whether allocated memory contains pointers to other allocated memory. In general, you must arrange that each pointer returned from malloc be individually passed to free, exactly once (if it is freed at all).

A good rule of thumb is that for each call to malloc in a program, you should be able to point at the call to free which frees the memory allocated by that malloc call. (In many cases, you'll free blocks of memory in the reverse order you allocated them, although this order is by no means required.)

See also question 7.24.




comp.lang.c FAQ list · Question 7.24

Q: Must I free allocated memory before the program exits?


A: You shouldn't have to. A real operating system definitively reclaims all memory and other resources when a program exits; the system cannot afford to have memory integrity depend on the whims of random programs. (Strictly speaking, it is not even free's job to return memory to the operating system; see question 7.25.) Nevertheless, some personal computers are said not to reliably recover memory unless it was freed before exiting, and all that can be inferred from the ANSI/ISO C Standard is that this is a ``quality of implementation issue.''

On the other hand, the C library free function rarely returns memory back to the operating system (see question 7.25), so calling free probably isn't the way to guarantee that an exiting program's memory is recovered by the system, anyway.

In any case, it can be considered good practice to explicitly free all memory--for example, in case the program is ever rewritten to perform its main task more than once (perhaps under a Graphical User Interface). [footnote] On the other hand, there are programs (such as interpreters) that don't know what memory they're done with (i.e. what memory could be freed) until it's time to exit, and since all memory should be released at exit, it would be a needless, potentially expensive, and error-prone exercise for the program to explicitly free all of it.

Additional links: further explanation

References: ISO Sec. 7.10.3.2




comp.lang.c FAQ list · Question 7.25

Q: I have a program which mallocs and later frees a lot of memory, but I can see from the operating system that memory usage doesn't actually go back down.


A: Most implementations of malloc/free do not return freed memory to the operating system, but merely make it available for future malloc calls within the same program.

Additional links: further reading




comp.lang.c FAQ list · Question 7.26

Q: How does free know how many bytes to free?


A: The malloc/free implementation remembers the size of each block as it is allocated, so it is not necessary to remind it of the size when freeing. (Typically, the size is stored adjacent to the allocated block, which is why things usually break badly if the bounds of the allocated block are even slightly overstepped; see also question 7.19.)




comp.lang.c FAQ list · Question 7.27

Q: So can I query the malloc package to find out how big an allocated block is?


A: Unfortunately, there is no standard or portable way. (Some compilers provide nonstandard extensions.) If you need to know, you'll have to keep track of it yourself. (See also question 7.28.)




comp.lang.c FAQ list · Question 7.28

Q: Why doesn't sizeof tell me the size of the block of memory pointed to by a pointer?


A: sizeof tells you the size of the pointer. There is no portable way to find out the size of a malloc'ed block. (Remember, too, that sizeof operates at compile time, and see also question 7.27.)




comp.lang.c FAQ list · Question 7.29

Q: Having dynamically allocated an array (as in question 6.14), can I change its size?


A: Yes. This is exactly what realloc is for. Given a region of malloced memory (such as dynarray from question 6.14), its size can be changed using code like:

	dynarray = realloc(dynarray, 20 * sizeof(int));
Note that realloc may not always be able to enlarge [footnote] memory regions in-place. When it is able to, it simply gives you back the same pointer you handed it, but if it must go to some other part of memory to find enough contiguous space, it will return a different pointer (and the previous pointer value will become unusable).

If realloc cannot find enough space at all, it returns a null pointer, and leaves the previous region allocated. [footnote] Therefore, you usually don't want to immediately assign the new pointer to the old variable. Instead, use a temporary pointer:

	#include <stdio.h>
	#include <stdlib.h>

	int *newarray = (int *)realloc((void *)dynarray, 20 * sizeof(int));
	if(newarray != NULL)
		dynarray = newarray;
	else {
		fprintf(stderr, "Can't reallocate memory\n");
		/* dynarray remains allocated */
	}

When reallocating memory, be careful if there are any other pointers lying around which point into (``alias'') that memory: if realloc must locate the new region somewhere else, those other pointers must also be adjusted. Here is a (contrived, and careless of malloc's return values) example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *p, *p2, *newp;
int tmpoffset;

p = malloc(10);
strcpy(p, "Hello,");		/* p is a string */
p2 = strchr(p, ',');		/* p2 points into that string */

tmpoffset = p2 - p;
newp = realloc(p, 20);
if(newp != NULL) {
	p = newp;		/* p may have moved */
	p2 = p + tmpoffset;	/* relocate p2 as well */
	strcpy(p2, ", world!");
}

printf("%s\n", p);
(It is safest to recompute pointers based on offsets, as in the code fragment above. The alternative--relocating pointers based on the difference, newp - p, between the base pointer's value before and after the realloc--is not guaranteed to work, because pointer subtraction is only defined when performed on pointers into the same object. See also question 7.21.)

See also questions 7.7 and 7.30.

References: K&R2 Sec. B5 p. 252
ISO Sec. 7.10.3.4
H&S Sec. 16.3 pp. 387-8




comp.lang.c FAQ list · Question 7.30

Q: Is it legal to pass a null pointer as the first argument to realloc? Why would you want to?


A: ANSI C sanctions this usage (and the related realloc(..., 0), which frees), although several earlier implementations do not support it, so it may not be fully portable. Passing an initially-null pointer to realloc can make it easier to write a self-starting incremental allocation algorithm.

Here is an example--this function reads an arbitrarily-long line into dynamically-allocated memory, reallocating the input buffer as necessary. (The caller must free the returned pointer when it is no longer needed.)

#include <stdio.h>
#include <stdlib.h>

/* read a line from fp into malloc'ed memory */
/* returns NULL on EOF or error */
/* (use feof or ferror to distinguish) */

char *agetline(FILE *fp)
{
	char *retbuf = NULL;
	size_t nchmax = 0;
	register int c;
	size_t nchread = 0;
	char *newbuf;

	while((c = getc(fp)) != EOF) {
		if(nchread >= nchmax) {
			nchmax += 20;
			if(nchread >= nchmax) {	/* in case nchmax overflowed */
				free(retbuf);
				return NULL;
			}
#ifdef SAFEREALLOC
			newbuf = realloc(retbuf, nchmax + 1);
#else
			if(retbuf == NULL)	/* in case pre-ANSI realloc */
				newbuf = malloc(nchmax + 1);
			else	newbuf = realloc(retbuf, nchmax + 1);
#endif
						/* +1 for \0 */
			if(newbuf == NULL) {
				free(retbuf);
				return NULL;
			}

			retbuf = newbuf;
		}

		if(c == '\n')
			break;

		retbuf[nchread++] = c;
	}

	if(retbuf != NULL) {
		retbuf[nchread] = '\0';

		newbuf = realloc(retbuf, nchread + 1);
		if(newbuf != NULL)
			retbuf = newbuf;
	}

	return retbuf;
}
(In production code, a line like nchmax += 20 can prove troublesome, as the function may do lots of reallocating. Many programmers favor multiplicative reallocation, e.g. nchmax *= 2, although it obviously isn't quite as self-starting, and can run into problems if it has to allocate a huge array but memory is limited.)

References: ISO Sec. 7.10.3.4
H&S Sec. 16.3 p. 388




comp.lang.c FAQ list · Question 7.31

Q: What's the difference between calloc and malloc? Which should I use? Is it safe to take advantage of calloc's zero-filling? Does free work on memory allocated with calloc, or do you need a cfree?


A: calloc(m, n) is essentially equivalent to

p = malloc(m * n);
memset(p, 0, m * n);

There is no important difference between the two other than the number of arguments and the zero fill.[footnote]

Use whichever function is convenient. Don't rely on calloc's zero fill too much (see below); usually, it's best to initialize data structures yourself, on a field-by-field basis, especially if there are pointer fields.

calloc's zero fill is all-bits-zero, and is therefore guaranteed to yield the value 0 for all integral types (including '\0' for character types). But it does not guarantee useful null pointer values (see section 5 of this list) or floating-point zero values.

free is properly used to free the memory allocated by calloc; there is no Standard cfree function.

One imagined distinction that is not significant between malloc and calloc is whether a single element or an array of elements is being allocated. Though calloc's two-argument calling convention suggests that it is supposed to be used to allocate an array of m items of size n, there is no such requirement; it is perfectly permissible to allocate one item with calloc (by passing one argument as 1) or to allocate an array with malloc (by doing the multiplication yourself; see for example the code fragment in question 6.14). (Nor does structure padding enter into the question; any padding necessary to make arrays of structures work correctly is always handled by the compiler, and reflected by sizeof. See question 2.13.)

References: ISO Sec. 7.10.3 to 7.10.3.2
H&S Sec. 16.1 p. 386, Sec. 16.2 p. 386
PCS Sec. 11 pp. 141,142




comp.lang.c FAQ list · Question 7.32

Q: What is alloca and why is its use discouraged?


A: alloca allocates memory which is automatically freed when the function which called alloca returns. That is, memory allocated with alloca is local to a particular function's ``stack frame'' or context.

alloca cannot be written portably, [footnote] and is difficult to implement on machines without a conventional stack. Its use is problematical (and the obvious implementation on a stack-based machine fails) when its return value is passed directly to another function, as in fgets(alloca(100), 100, stdin). [footnote]

For these reasons, alloca is not Standard and cannot be used in programs which must be widely portable, no matter how useful it might be. Now that C99 supports variable-length arrays (VLA's), they can be used to more cleanly accomplish most of the tasks which alloca used to be put to.

See also question 7.22.

Additional links: an article by Gordon L. Burditt describing difficulties in implementing and using alloca

References: Rationale Sec. 4.10.3





Read sequentially: prev next up



about this FAQ list   about eskimo   search   feedback   copyright

Hosted by Eskimo North