一尘不染

C是否有任何用于进行字符串加法的工具?

algorithm

我正在做一个函数,该函数返回表示为树的函数的派生类,例如

      /   +    \
     *          ^
   /   \      /   \
  x     5   3.14   x

具有以下形式的节点

typedef struct node
{
    char * fx; // function
    struct node * gx; // left-hand side
    char * op; // operator
    struct node * hx; // right-hand side
} node;

如果一个节点没有子节点,例如x53.14在上述例子中,那么它的opgx并且hxNULL,否则其fxNULL

我的计算导数的函数看起来像

char * deriveFromTree ( node * rt )
{
    char * buff = malloc(100*sizeof(char));
    int curBuffIdx = 0;
    if (rt->op) // if rt is of the form rt = gx op hx
    {
        char * dgdx = deriveFromTree(rt->gx); // g'(x)
        char * dhdx = deriveFromTree(rt->hx); // h'(x)
        char thisop = *rt->op;
        if (thisop == '+' || thisop == '-')
        {
            // ... want to do equivalent of
            //     buff = dgdx + thisop + dhdx
        }
        else if (thisop == '*')
        {
            // ...
        }
        else if (thisop == '/')
        {
            // ...
        }
        else if (thisop == '^')
        {
            // ...
        }
    }
    else // rt is a base expression -- x or a constant
    {
        buff[curBuffIdx] = strcmp(rt->fx, 'x') ? '1': '0';
    }
    buff[++curBuffIdx] = '\0';
    return buff;
}

但是我对所有字符串的添加都感到迷恋。如果已经有一种紧凑的方法,我可以从头开始创建一个字符串加法器

            // ... want to do equivalent of
            //     buff = dgdx + thisop + dhdx

然后我想使用该工具。


阅读 245

收藏
2020-07-28

共1个答案

一尘不染

如果您的C标准库是GNU或*
BSD,那么您可能已经asprintf可以使用。但是,您可能需要启用功能测试宏才能使用它。如果没有asprintf,可以根据C标准vsnprintf功能轻松定义。

asprintf以新分配的字符串形式返回格式的结果(这是您的责任free)。因此,您可以编写例如:

char* buff;
int n = asprintf(&buff, "%s%c%s", dgdx, thisop, dhdx);

我通常使用包装函数,该函数返回字符串而不是长度,因此您可以编写:

char* buff = concatf("%s%c%s", dgdx, thisop, dhdx);

这是三个简单的实现;第一个将在具有的系统上工作vasprintf; 第二点在Posix系统上vsnprintf;
第三个用于Windows,显然实现了不同的snprintf界面。

// Version 1, systems which have vasprintf:
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;
}

// Version 2: Systems without vasprintf but with vsnprintf
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;
}

// Version 3: Windows
// Apparently, the implementation of vsnprintf on Windows returns -1
// if not enough space has been provided. So here is the above code
// rewritten according to the documentation I found in
//  https://msdn.microsoft.com/en-us/library/w05tbk72%28VS.71%29.aspx
// and
//  https://msdn.microsoft.com/en-us/library/1kt27hek%28v=vs.71%29.aspx
// but totally untested. (If you try it, let me know)
char* concatf(const char* fmt, ...) {
  char* buf = NULL;
  va_list args;
  va_start(args, fmt);
  int n = _vscprintf(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;
}

这是我所知道的其他语言中的字符串连接运算符最简洁的等效项。(它不一定在执行时间上是最高效的,但可能是在程序员时间内。)

2020-07-28