有些情况下我们想让函数返回一个由该函数初始化的字符串。假设我们想传递一个部件的信息,比如名字和数量,然后让函数返回表示这个信息的格式化字符串。通过把格式化处理放在函数内部,我们可以在程序的不同部分重用这个函数。
不过,我们得决定是给函数传递一个空缓冲区让它填充并返回,还是让函数动态分配缓冲区并返回。
要传递缓冲区:
- 必须传递缓冲区的地址和长度;
- 调用者负责释放缓冲区;
- 函数通常返回缓冲区的指针。
这种方法把分配和释放缓冲区的责任都交给了调用者。虽然没有必要,返回缓冲区指针很常见,strcpy
或类似函数就是这种情况。下面的format
函数说明了这种方法:
char* format(char *buffer, size_t size,
const char* name, size_t quantity, size_t weight) {
snprintf(buffer, size, "Item: %s Quantity: %u Weight: %u",
name, quantity, weight);
return buffer;
}
这里用了snprintf
函数来简化字符串格式化,该函数写入第一个参数指向的缓冲区。第二个参数指定缓冲区的长度,函数不会越过缓冲区写入。其他方面,这个函数和printf
函数的行为一样。
下面的语句说明了这个函数的用法。它假设缓冲区已被声明为一个数组。如果已动态分配缓冲区内存,则需要传入分配的内存大小,而不是使用函数的大小。
printf("%s\n",format(buffer,sizeof(buffer),"Axle",25,45));
输出如下:
Item: Axle Quantity: 25 Weight: 45
通过返回缓冲区的指针,我们可以将函数作为printf
函数的参数。
还有一种方法是传递NULL
作为缓冲区地址,这表示调用者不想提供缓冲区,或者它不确定缓冲区应该是多大。这样的函数实现列在了下面,在计算长度时,10 + 10
子表达式表示数量和重量可能的最大宽度,而1则是为NUL
终结符留下空间:
char* format(char *buffer, size_t size,
const char* name, size_t quantity, size_t weight) {
char *formatString = "Item: %s Quantity: %u Weight: %u";
size_t formatStringLength = strlen(formatString)-6;
size_t nameLength = strlen(name);
size_t length = formatStringLength + nameLength +
10 + 10 + 1;
if(buffer == NULL) {
buffer = (char*)malloc(length);
size = length;
}
snprintf(buffer, size, formatString, name, quantity, weight);
return buffer;
}
函数使用的变量取决于应用程序的需要。第二种方法的主要缺点在于调用者现在要负责释放分配的内存,调用者需要对函数的使用方法了如指掌,否则可能很容易产生内存泄漏。