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

时间:2014-06-27 00:52:46

标签: 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), vals(u->right);
    }
}

我不知道如何写这个,因为我找不到与form类似的功能。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

/* 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的一部分:

char* concatf(const char* fmt, ...) {
  va_list args;
  char* buf = NULL;
  va_start(args, fmt);
  int n = vasprintf(&buf, fmt, args);
  va_end(args);
  if (n < 0) { free(buf); buf = NULL; }
  return buf;
}

第二个依赖于vsnprintf,它是一个Posix标准接口,但在一些较旧的标准C库实现中被错误地实现(例如,glibc直到版本2.0.6。)

char* concatf(const char* fmt, ...) {
  va_list args;
  va_start(args, fmt);
  char* buf = NULL;
  int n = vsnprintf(NULL, 0, fmt, args);
  va_end(args);
  if (n >= 0) {
    va_start(args, fmt);
    buf = malloc(n+1);
    if (buf) vsnprintf(buf, n+1, fmt, args);
    va_end(args);
  }
  return buf;
}

随意使用它们。他们并不是特别深刻。

对于gcc(我认为是clang),你可以将函数声明为:

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

这将使编译器能够检查格式字符串的有效性,就像使用printf

一样

答案 2 :(得分:0)

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

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);
    }
}