数组的大小可以在程序运行时定义吗?
不。在数组的定义中,数组的大小必须是编译时可知的,不能是在程序运行时才可知的。例如,假设i是一个变量,你就不能用i去定义一个数组的大小:
char array[i]; /*(notvalidc */
有些语言支持这种定义,但C语言不支持。如果C语言支持这种定义,栈就会变得更复杂,调用函数的开销就会更大,而程序的运行速度就会明显变慢。
如果数组的大小在编译时是可知的,即使它是一个非常复杂的表达式,只要它在编译时能被计算出来,你就可以定义它。
如果你要使用一个在程序运行时才知道其大小的数组,你可以说明一个指针,并且调用malloc()或calloc()函数从堆中为这个数组分配内存空间。以下是一个拷贝传给main()函数的argv数组的例子:
- 例 7.15 在动行时确定大小的数组,使用了指针和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 + l, 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-l])
- */
- for (i = 0;i<argc; + +i)
- {
- / * make room for '\0' at end, too * /
- new_argv [i]= (char* ) malloc(strlen(argv[i]) + l);
- strcpy(new_argv[i], argv[i]);
- printf ("allocated %d bytes for new_argv[%d] at %P",
- "copied\"%s\"\n",
- strlen(argv[i]) + l, 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 poiners 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; /* 习惯,见本例后面的注意 */
- }
- free(new_argv);
- printf("freed new_argv itself at %P\n",new_argv);
- return 0; /*请参见16.4 */
- }
注意:为什么例7.5在释放了new_argv数组中的每个元素之后,还要将这些元素赋值为NULL呢?这是一种在长期实践的基础上形成的习惯。在释放了一个指针之后,你就无法再使用它原来所指向的数据了,或者说,该指针被“悬挂”起来了,它不再指向任何有用的数据。如果在释放一个指针之后立即将它赋值为NULL,那么,即使程序再次使用该指针,程序也不会出错。当然,程序可能会间接引用这个空指针,但这种错误在调试程序时就能及时被发现。此外,
程序中可能仍然有一些该指针原来的拷贝,它们仍然指向已被释放的那部分内存空间,这种情况在C程序中是很自然的。总之,尽管上述这种习惯并不能解决所有问题,但确实有作用。