我正在做一个函数,该函数返回表示为树的函数的派生类,例如
/ + \ * ^ / \ / \ 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,gx并且hx是NULL,否则其fx是NULL。
x
5
3.14
op
gx
hx
NULL
fx
我的计算导数的函数看起来像
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标准库是GNU或* BSD,那么您可能已经asprintf可以使用。但是,您可能需要启用功能测试宏才能使用它。如果没有asprintf,可以根据C标准vsnprintf功能轻松定义。
asprintf
vsnprintf
asprintf以新分配的字符串形式返回格式的结果(这是您的责任free)。因此,您可以编写例如:
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界面。
vasprintf
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; }
这是我所知道的其他语言中的字符串连接运算符最简洁的等效项。(它不一定在执行时间上是最高效的,但可能是在程序员时间内。)