c - 关于函数返回的 char 指针的最佳实践
问题描述
处理返回指向 C 字符串的 malloc 指针的函数时,最佳实践是什么?
这是一个例子:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
tmp = concat(fn, i);
f = fopen(tmp, "w");
free(tmp);
// read f, do something useful ...
fclose(f);
}
char* concat(char *a, int b)
返回一个指向新 C 字符串的指针,其中包含 和 的a
连接b
。
我不仅必须指定一个临时指针,然后将其传递给fopen
,我还必须free(tmp)
每次都这样做。我宁愿喜欢这样的东西:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
f = fopen(concat(fn, i), "w");
// read f, do something useful ...
fclose(f);
}
但这当然会导致内存泄漏。那么这里的最佳实践是什么?类似于concat(char *a, int b, char *result)
where result 应该是生成的 C 字符串的预分配内存之类的东西?此解决方案有其缺点,例如result
.
解决方案
这两种方法都在工业中使用。在您的示例中,人们可以假设生成的文件名的最大大小并以这种方式使用本地数组:
for (int i = 0; i <= 10; i++) {
char filename[1024];
snprintf(filename, sizeof filename, "%s%d", fn. i);
FILE *f = fopen(filename, "w");
if (f != NULL) {
// read f, do something useful ...
fclose(f);
} else {
// report the error?
}
}
请注意,可以使用 检测截断if (snprintf(filename, sizeof filename, "%s%d", fn. i) >= (int)sizeof filename)
。
如果不应该对文件名长度做出假设,或者文件名组合方法更复杂,则返回分配的字符串可能是更合适的选择,但也应该测试内存分配错误:
for (int i = 0; i <= 10; i++) {
char *filename = concat(fn, i);
if (filename == NULL) {
/* handle the error */
...
// break / continue / return -1 / exit(1) ...
}
FILE *f = fopen(filename, "w");
if (f == NULL) {
/* report this error, using `filename` for an informative message */
} else {
// read f, do something useful...
// keep `filename` available for other reporting
fclose(f);
}
free(filename);
}
如果您还没有准备好执行所有这些簿记,您可能应该使用具有更精细的对象生命周期管理或垃圾收集器的不同语言。
最后,使用 C99 复合文字,您可以定义concat
以适合您的简化用例:
char *concat(char *dest, const char *s, int b) {
sprintf(dest, "%s%d", s, b);
return dest;
}
#define CONCAT(a, b) concat((char[strlen(a) + 24]){""}, a, b)
CONCAT
char
定义了一个适当大小的未命名的局部可变长度数组,并在其中构造了 stringa
和 int的连接b
。我将大小写更改为大写以强调在扩展中被评估两次的事实,a
因此不应该是涉及副作用的表达式。
您可以在第二个代码片段中按预期使用此宏:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
f = fopen(CONCAT(fn, i), "w");
// read f, do something useful ...
fclose(f);
}
我可能不会推荐这种用法,但这只是我的意见。
推荐阅读
- javascript - 在页面加载时接收字典
- java - 是什么让这个散列函数具有内射性?
- javascript - 如何获取 Cloud Firestore 查询返回的数据?
- powershell - 显示“大括号”符号值的变量的写入输出
- git - “git diff”以绿色突出显示所有内容 - 不是新更改
- c++ - 如何修复潜在的缓冲区溢出。(警告 C6385)以及超过 1 个字节的潜在读数(警告 C6385)
- javascript - 一个 Promise 中的两个拒绝
- python-3.x - 在 logger.warning 调用中使单元测试失败
- python - Python参考问题,这会导致内存泄漏吗
- java - 无法制作正确的表格,GPA 计算不会返回正确的成绩