Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
355 views
in Technique[技术] by (71.8m points)

Does C have any tools for doing string addition?

I'm making a function that returns the derivative of a function that is represented as a tree like

      /   +    
     *          ^
   /         /   
  x     5   3.14   x

with nodes of the form

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

If a node has no children, e.g. x, 5, 3.14 in the above example, then its op, gx and hx are NULL, and otherwise its fx is NULL.

My function for calculating the derivative looks like

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] = '';
    return buff;
}

but I'm getting tripped up on all the string addition. I could create from scratch a string adder, if there's already a compact way of doing

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

then I'd like to use that tool.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If your C standard library is GNU or *BSD, then you probably have asprintf available. You may need to enable a feature test macro to use it, though. If you don't have asprintf available, it can easily be defined in terms of the C standard vsnprintf function.

asprintf returns the result of the format as a newly-allocated string (which it is your responsibility to free). So you could write, for example:

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

I usually use a wrapper function, which returns the string rather than the length, so you can write:

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

Here are three simple implementations; the first will work on systems with vasprintf; the second on systems with Posix vsnprintf; and the third for Windows, which apparently implements a different snprintf interface.

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

That's the most concise equivalent I know of to string concatenation operators in other languages. (It's not necessarily the most efficient in execution time, but it probably is in programmer time.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...