Tuesday 8 November 2011

Can the size of an array be declared at runtime? in C programming

Can the size of an array be declared at runtime?

No. In an array declaration, the size must be known at compile time. You can’t specify a size that’s known
only at runtime. For example, if i is a variable, you can’t write code like this:
char array[i]; /* not valid C */
Some languages provide this latitude. C doesn’t. If it did, the stack (see FAQ VII.20) would be more
complicated, function calls would be more expensive, and programs would run a lot slower.
If you know that you have an array but you won’t know until runtime how big it will be, declare a pointer
to it and use malloc() or calloc() to allocate the array from the heap.

If you know at compile time how big an array is, you can declare its size at compile time. Even if the size is
some complicated expression, as long as it can be evaluated at compile time, it can be used.

Listing VII.15 shows an example. It’s a program that copies the argv array passed to main().

Arrays with runtime size, using pointers and malloc().

/*
A silly program that copies the argv array and all the pointed-to
strings. Just for fun, it also deallocates all the copies.
*/
#include <stdlib.h>
#include <string.h>
int
main(int argc, char** argv)
{
char** new_argv;
int i;
/*
Since argv[0] through argv[argc] are all valid, the
program needs to allocate room for argc+1 pointers.
*/
new_argv = (char**) calloc(argc+1, sizeof (char*));
/* or malloc((argc+1) * sizeof (char*)) */
printf(“allocated room for %d pointers starting at %P\n”,
argc+1, new_argv);
/*
now copy all the strings themselves
(argv[0] through argv[argc-1])
*/
for (i = 0; i < argc; ++i) {
/* make room for ‘\0’ at end, too */
new_argv[i] = (char*) malloc(strlen(argv[i]) + 1);
strcpy(new_argv[i], argv[i]);
printf(“allocated %d bytes for new_argv[%d] at %P, “
“copied \”%s\”\n”,
strlen(argv[i]) + 1, i, new_argv[i], new_argv[i]);
}
new_argv[argc] = NULL;
/*
To deallocate everything, get rid of the strings (in any
order), then the array of pointers. If you free the array
of pointers first, you lose all reference to the copied
strings.
*/
for (i = 0; i < argc; ++i) {
free(new_argv[i]);
printf(“freed new_argv[%d] at %P\n”, i, new_argv[i]);
argv[i] = NULL; /* paranoia; see note */
}
free(new_argv);
printf(“freed new_argv itself at %P\n”, new_argv);
return 0; /* see FAQ XVI.4 */
}

NOTE
Why does the program in Listing VII.15 assign NULL to the elements in new_argv after freeing them? This is paranoia based on long experience. After a pointer has been freed, you can no longer use the pointed-to data. The pointer is said to “dangle”; it doesn’t point at anything useful. If youn “NULL out” or “zero out” a pointer immediately after freeing it, your program can no longer get in trouble by using that pointer. True, you might go indirect on the null pointer instead, but that’s something your debugger might be able to help you with immediately. Also, there still might be copies of the pointer that refer to the memory that has been deallocated; that’s the nature of C. Zeroing out pointers after freeing them won’t solve all problems; it can solve some. See FAQ VII.22 for a related discussion.

Cross Reference:

VII.16: Is it better to use malloc() or calloc()?
VII.20: What is the stack?
VII.21: What is the heap?
VII.22: What happens if you free a pointer twice?
IX.8: Why can’t constant values be used to define an array’s initial size?

No comments:

Post a Comment