数组的大小可以在程序运行时定义吗?
不。在数组的定义中,数组的大小必须是编译时可知的,不能是在程序运行时才可知的。例如,假设i是一个变量,你就不能用i去定义一个数组的大小:
char array[i]; /*(notvalidc */
有些语言支持这种定义,但C语言不支持。如果C语言支持这种定义,栈就会变得更复杂,调用函数的开销就会更大,而程序的运行速度就会明显变慢。
如果数组的大小在编译时是可知的,即使它是一个非常复杂的表达式,只要它在编译时能被计算出来,你就可以定义它。
如果你要使用一个在程序运行时才知道其大小的数组,你可以说明一个指针,并且调用malloc()或calloc()函数从堆中为这个数组分配内存空间。以下是一个拷贝传给main()函数的argv数组的例子:

  1. 例 7.15 在动行时确定大小的数组,使用了指针和malloc()   
  2. /*  
  3. A silly program that copies the argv array and all the pointed-to  
  4. strings. Just for fun, it also deallocates all the copies.  
  5. */   
  6. # include <stdlib. h>   
  7. # include <string. h>   
  8. int   
  9. main (int argc, char* * argv)   
  10. {   
  11. char* * new_argv;   
  12. int i;   
  13. /*  
  14. Since argv[0] through argv [argc] are all valid, the  
  15. program needs to allocate room for argc + 1 pointers.  
  16. */   
  17. new_argv = (char* * ) calloc(argc + l, sizeof (char * ));   
  18. / * or malloc ((argc +1) * sizeof (char * ) ) * /   
  19. printf ("allocated room for %d pointers starting at %P\n", argc + 1, new_argv);   
  20. /*  
  21. now copy all the strings themselves  
  22. (argv[0] through argv[argc-l])  
  23. */   
  24. for (i = 0;i<argc; + +i)   
  25. {   
  26. / * make room for '\0' at end, too * /   
  27. new_argv [i]= (char* ) malloc(strlen(argv[i]) + l);   
  28. strcpy(new_argv[i], argv[i]);   
  29. printf ("allocated %d bytes for new_argv[%d] at %P",   
  30. "copied\"%s\"\n",   
  31. strlen(argv[i]) + l, i, new_argv[i], new_argv[i]) ;   
  32. }   
  33. new_ argv [argc] = NULL:   
  34. /*  
  35. To deallocate everything, get rid of the strings (in any  
  36. order), then the array of pointers. If you free the array  
  37. of poiners first, you lose all reference to the copied  
  38. strings.  
  39. */   
  40. for (i = 0;i<argc; ++i) {   
  41. free(new_argv[i]);   
  42. printf ("freed new_argv[%d] at %P\n" , i, new_argv[i]) ;   
  43. argv[i]=NULL; /* 习惯,见本例后面的注意 */   
  44. }   
  45. free(new_argv);   
  46. printf("freed new_argv itself at %P\n",new_argv);   
  47. return 0; /*请参见16.4 */   
  48. }   

注意:为什么例7.5在释放了new_argv数组中的每个元素之后,还要将这些元素赋值为NULL呢?这是一种在长期实践的基础上形成的习惯。在释放了一个指针之后,你就无法再使用它原来所指向的数据了,或者说,该指针被“悬挂”起来了,它不再指向任何有用的数据。如果在释放一个指针之后立即将它赋值为NULL,那么,即使程序再次使用该指针,程序也不会出错。当然,程序可能会间接引用这个空指针,但这种错误在调试程序时就能及时被发现。此外,
程序中可能仍然有一些该指针原来的拷贝,它们仍然指向已被释放的那部分内存空间,这种情况在C程序中是很自然的。总之,尽管上述这种习惯并不能解决所有问题,但确实有作用。