C99标准里规定了允许在栈上定义变长数组或者叫变长自动数组(Variable-length Automatic Array). 例如:
/* s1 and s2 are two strings(char*) */ char str[strlen (s1) + strlen (s2) + 1]; /* str 就是栈上的变长数组 */ strcpy (str, s1); strcat (str, s2);
栈上的变长数组比堆上的变长数组有什么好处呢?
1. 不需要担心内存回收,数组变量在超出作用域后会自动回收;
2. 对于多维数组使用尤为方便,例如:
int arr[m][n][k]; int ***p = (int***)malloc(sizeof(int) * m * n * k); /* 这样使用不如 arr 直观方便 */
gcc在这方面早就有了很好的支持,我实际试的是在3.x版就已经支持了,而且,对于C90和C++都支持。
另外,gcc还增加了一个函数:alloca()
类似malloc(),只是alloca()分配的内存是在栈上。
alloca() 和栈上的变长数组的区别在于,alloca() 的分配的内存有效范围是在整个函数内部,而变长数组的有效范围是 { } 之间,例如:
void func(void) { int *p = NULL; if (xxx) { p = alloca(sizeof(int)); /* alloca分配的内存在if语句外也可以使用. */ int arr[n]; /* arr的有效范围在if语句内. */ ... } ... }
不过需要注意的是,如果alloca和变长数组在同一个函数里混用时,当一个变长数组被销毁时,在他之后调用的alloca分配的内存也将被销毁。这是gcc manual中的原文:
If you use both variable-length arrays and alloca in the same function, deallocation of a variable-length array will also deallocate anything more recently allocated with alloca.
这点很好理解,变长数组和alloca都是在栈上分配内存,编译器在对栈上的变量销毁时只是简单的弹栈,如下:
if (xxx) { int arr[n]; p = alloca(xxx); } 上面这段代码执行时栈的变化: | | top-->| | | | top-->| | | p | | p |已经无效了! |arr| |arr| |arr|弹栈,销毁arr |...| |...| top-->|...| +---+ +---+ +---+ (1)分配arr空间 (2)分配p的空间 (3)销毁arr时p同时被销毁
因此,虽然alloca和变长数组可以给我们带来方便,但使用时一定要小心!