如果需要从函数返回字符串,我们可以在堆上分配字符串的内存然后返回其地址。我们会开发一个blanks
函数来说明这种技术,这个函数会返回一个包含一系列代表“制表符”的空白的字符串,如下所示。函数接受一个指定制表符序列长度的整数参数:
char* blanks(int number) {
char* spaces = (char*) malloc(number + 1);
int i;
for (i = 0; i<number; i++) {
spaces[i] = ' ';
}
spaces[number] = '\0';
return spaces;
}
...
char *tmp = blanks(5);
将NUL
终结符赋给由number
索引的数组的最后一个元素,下图说明了本例的内存分配,它显示了blanks
函数返回前后应用程序的状态。
释放返回的内存是函数调用者的责任,如果不再需要内存但没有将其释放会造成内存泄漏。下面是一个内存泄漏的例子,printf
函数中使用了字符串,但是接着它的地址就丢失了,因为我们没有保存:
printf("[%s]\n",blanks(5));
一个更安全的方法如下所示:
char *tmp = blanks(5);
printf("[%s]\n",tmp);
free(tmp);
返回局部字符串的地址
返回局部字符串的地址可能会有问题,如果内存被别的栈帧覆写就会损坏,应该避免使用这种方法,这里作解释只是为了说明实际使用这种方法的潜在问题。
我们重写前面的blanks
函数,如下所示。在函数内部声明一个数组,而不是动态分配内存,这个数组位于栈帧上。函数返回数组的地址:
#define MAX_TAB_LENGTH 32
char* blanks(int number) {
char spaces[MAX_TAB_LENGTH];
int i;
for (i = 0; i < number && i < MAX_TAB_LENGTH; i++) {
spaces[i] = ' ';
}
spaces[i] = '\0';
return spaces;
}
执行函数后会返回数组的地址,但是之后下一次函数调用会覆写这块内存区域。解引指针后该内存地址的内容可能已经改变。下图说明了程序栈的状态。