【问题标题】:Does C have any tools for doing string addition?C是否有任何工具可以进行字符串加法?
【发布时间】:2015-08-21 12:01:04
【问题描述】:

我正在创建一个函数,该函数返回一个函数的导数,该函数表示为一棵树

      /   +    \
     *          ^
   /   \      /   \
  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;

如果一个节点没有子节点,例如x, 5, 3.14 在上面的例子中,那么它的op, gxhxNULL,否则它的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

那么我想使用那个工具。

【问题讨论】:

  • C 使用的唯一“工具”是编译器。否则,您可能会看一下您显然已经在使用的标准字符串库。另外:什么是“字符串添加”?
  • strcat ....或者我误解了你的问题
  • 通常,“字符串添加”被解释为连接。更准确地说你想做的是“浮点加法,其中数字以十进制表示形式存储在字符串中”?
  • 我的个人偏好取决于可用的功能。如果我有动态分配内存功能(malloc),我将使用动态字符串库,类似于 C++ 自己的std::string 类型,这将允许我根据需要增长字符串。否则,我将使用功能类似于非标准 C 函数 strlcat 的东西,它将截断标记为错误,因为允许信息丢失绝不是一个好主意。

标签: c string algorithm data-structures tree


【解决方案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;
}

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

【讨论】:

    【解决方案2】:

    您正在寻找的是字符串连接,标准 C 库函数是 strcat,或者更好(因为可以说更安全)strncat

    http://linux.die.net/man/3/strcat

    【讨论】:

    • strncat 并不安全。它有自己的蠕虫罐头,例如如果缓冲区不够大,则不添加空终止符
    • 截断不安全。例如:假设您正在使用这些衍生物来控制车辆......
    • @bolov:我会很好地调用一个确实防止缓冲区溢出的函数——不管其他问题——调用比更安全.后面的NUL 可以很容易地添加到函数之后,缓冲区溢出不能。
    • 只要您知道strcat strncatstrlcat 中的任何一个的含义,并采取措施保护自己,一切都很好。如果你忽略它们,一切都不好。 IE。您可以将strcat 包装在if 中,这很好,或者您不能在strncat 之后附加空终止符,然后将该缓冲区传递给printf 之类的东西,您就完蛋了。跨度>
    • @KarolyHorvath:你有 52000+ 代表。你应该知道最好不要被争吵所激怒。奥拉夫,我认为卡罗利在安全方面同意你的观点,你们两个只是在如何正确地说什么更可怕方面存在分歧。不要个人化。
    【解决方案3】:

    您想要实现的目标无法用纯 C 语言完成,因为它没有运算符重载。您可以为此使用strncat,但请注意,这是一个非常低级的解决方案,需要您手动管理内存。

    您可以在 C++ 中使用 std::stringstd::wstring 对象干净地完成此操作,它们具有正确的 operator+()

    或者,您可以使用适当的面向对象的 API 实现自己的字符串结构。

    【讨论】:

      猜你喜欢
      • 2017-04-14
      • 1970-01-01
      • 2013-05-27
      • 2012-04-26
      • 2011-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多