从C函数返回格式化字符串

从C函数返回格式化字符串,c,string-formatting,C,String Formatting,我正在尝试编写一个递归函数,用于打印树状结构。我想做的大致如下。假设form是一个函数,它接受与printf相同的参数,但返回格式化字符串而不是打印它;Node是构建结构的基础结构,其中val插槽存储无符号长字符串 char* vals(Node* u) { if (leaf(u)) { return form("%lu", u->val); } else { return form("%s, %s", vals(u->left), v

我正在尝试编写一个递归函数,用于打印树状结构。我想做的大致如下。假设form是一个函数,它接受与printf相同的参数,但返回格式化字符串而不是打印它;Node是构建结构的基础结构,其中val插槽存储无符号长字符串

char* vals(Node* u) {
    if (leaf(u)) {
        return form("%lu", u->val);
    } else {
        return form("%s, %s", vals(u->left), vals(u->right);
    }
}

我不知道如何写这个,因为我找不到类似于表单的函数。

您可能正在寻找asprintf?请注意,一旦您使用了以前收到的分配字符串,并且不再需要它们,即在使用它们的asprintf和返回之间,您也应该释放它们,因此您需要一个中间变量。

您可能正在寻找asprintf?请注意,一旦使用了以前收到的分配字符串,并且不再需要它们,即在使用它们的asprintf和返回之间,您也应该释放它们,因此您需要一个中间变量。

我建议创建两个表单函数,一个用于叶节点,另一个用于非叶节点

char* formLeaf(Node* u) {
    char leafRet[100];
    sprintf(leafRet,"%lu", u->val); 
    return strdup(leafRet);
}

char* vals(Node* u);

char* formNonLeaf(Node* u) {
    char* left = vals(u->left);
    char* right = vals(u->left);
    char* ret = malloc(strlen(left) + strlen(right) + 3);
    sprintf(ret, "%s, %s", left, right);
    free(left);
    free(right);
    return ret;
}

char* vals(Node* u) {
    if (leaf(u)) {
        return formLeaf(u);
    } else {
        return formNonLeaf(u);
    }
}

我建议创建两个表单函数,一个用于叶节点,另一个用于非叶节点

char* formLeaf(Node* u) {
    char leafRet[100];
    sprintf(leafRet,"%lu", u->val); 
    return strdup(leafRet);
}

char* vals(Node* u);

char* formNonLeaf(Node* u) {
    char* left = vals(u->left);
    char* right = vals(u->left);
    char* ret = malloc(strlen(left) + strlen(right) + 3);
    sprintf(ret, "%s, %s", left, right);
    free(left);
    free(right);
    return ret;
}

char* vals(Node* u) {
    if (leaf(u)) {
        return formLeaf(u);
    } else {
        return formNonLeaf(u);
    }
}

碰巧,我有一个实现,两个实现,实际上是第77行左右的函数的实现。它只是一个简单的包装器,旨在使调用函数更容易;有更有效的解决方案,但通常没有多大区别

/* Like GNU asprintf, but returns the resulting string buffer;
 * it is the responsibility of the caller to freee the buffer
 */
char* concatf(const char* fmt, ...);
第一个依赖于vasprintf,这是一个非标准函数,是Gnu glibc的一部分:

您可以根据需要随意使用它们。它们不是特别深刻

对于gcc和clang,我认为您可以将函数声明为:

char* concatf(const char *fmt, ...)
      __attribute__ ((format (printf, 1, 2)));

这将使编译器能够检查格式字符串的有效性,就像它在printf中所做的那样。我有两个实现,实际上是在第77行左右。它只是一个简单的包装器,旨在使调用函数更容易;有更有效的解决方案,但通常没有多大区别

/* Like GNU asprintf, but returns the resulting string buffer;
 * it is the responsibility of the caller to freee the buffer
 */
char* concatf(const char* fmt, ...);
第一个依赖于vasprintf,这是一个非标准函数,是Gnu glibc的一部分:

您可以根据需要随意使用它们。它们不是特别深刻

对于gcc和clang,我认为您可以将函数声明为:

char* concatf(const char *fmt, ...)
      __attribute__ ((format (printf, 1, 2)));

这将使编译器能够检查格式字符串的有效性,就像它对printf所做的那样

我不确定“但是返回格式化字符串而不是打印它”是什么意思“…你在找sprintf吗?可能是@mafso的复制品是的,它似乎就是我要找的。谢谢。sprintf/asprintf确实是你提出的特定问题的答案。如果你的问题是如何编写类似sprintf的东西,你将不得不malloc一块内存来构建字符串并处理r的问题E根据需要进行定位,以确保您永远不会试图写入超过该缓冲区的结尾,并且您必须管理指向该缓冲区的指针,以便适当地附加到该缓冲区。使用现成的可附加字符缓冲区库可以为您处理这些问题。@keshlam:此外,我们需要记住,在写入后必须释放内存返回,否则我们将有大量内存泄漏。但这不是不能立即解决的问题。我不确定“但返回格式化字符串而不是打印”是什么意思“…你在找sprintf吗?可能是@mafso的复制品是的,它似乎就是我要找的。谢谢。sprintf/asprintf确实是你提出的特定问题的答案。如果你的问题是如何编写类似sprintf的东西,你将不得不malloc一块内存来构建字符串并处理r的问题E根据需要进行定位,以确保您永远不会试图写入超过该缓冲区的结尾,并且您必须管理指向该缓冲区的指针,以便适当地附加到该缓冲区。使用现成的可附加字符缓冲区库可以为您处理这些问题。@keshlam:此外,我们需要记住,在写入后必须释放内存返回,否则我们将有大量内存泄漏。但这不是无法立即解决的问题。请注意,asprintf虽然方便,但不是可移植的,而是glib固有的。请注意,asprintf虽然方便,但不是可移植的,而是glib固有的。