以下出自“C Programming FAQS”.
先看下面的代码:
struct name {
int namelen;
char namestr[1];
};
struct name *makename(char *newname) {
struct name *ret = malloc(sizeof(struct name) - 1 + strlen(newname) + 1);
//-1 for initial [1]; +1 for \0
if(ret != NULL) {
ret->namelen = strlen(newname);
strcpy(ret->namestr, newname);
}
return ret;
}
这个函数分配了一个name结构的实例并调整它的大小,以便将请求的名称置入namestr域中。
也可以把变长的元素声明为很大,而不是很小。
#define MAX 100
struct name {
int namelen;
char namestr[MAX];
};
struct name *makename(char *newname) {
struct name *ret = malloc(sizeof(struct name) - MAX + strlen(newname) + 1);
if(ret != NULL) {
ret->namelen = strlen(newname);
strcpy(ret->namestr, newname);
}
return ret;
}
当然,真正安全的正确做法是使用字符指针,而不是数组。
struct name {
int namelen;
char *namep;
};
struct name *makename(char *newname) {
struct name *ret = malloc(sizeof(struct name));
if(ret != NULL) {
ret->namelen = strlen(newname);
ret->namep = malloc(ret->namelen + 1);
if(ret->namep == NULL) {
free(ret);
ret = NULL;
}
strcpy(ret->namep, newname);
}
return ret;
}
以上代码需要申请和释放没存空间两次。考虑到存储的数据类型是字符,为了保持连续性,可以直截了当的将两次malloc调用合成一次,这样也就可以只用一次调用free就能释放了。
struct name *makename(char *newname) {
char *buf = malloc(sizeof(struct name) + strlen(newname) + 1);
struct name *ret = (struct name *)buf;
ret->namelen = strlen(newname);
ret->namep = buf + sizeof(struct name);
strcpy(ret->namep, newname);
return ret;
}
但是,像这样用一次malloc调用将第二个区域接上的技巧只有在第二个区域是char型数组的时候才能移植。对于任何大一些的类型,对齐就变得很重要,必须保持。
C99引入了“灵活数组域”概念,允许结构的最后一个域省略数组的大小。