C 是否有任何用于执行字符串添加的工具?
Does C have any tools for doing string addition?
我正在制作一个函数,该函数 returns 表示为树状函数的导数
/ + \
* ^
/ \ / \
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;
如果一个节点没有children,例如上例中的x
、5
、3.14
,则其op
、gx
、hx
为NULL
,否则它的 fx
是 NULL
.
我计算导数的函数看起来像
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] = '[=12=]';
return buff;
}
但是我在所有的字符串添加上都被绊倒了。我可以从头开始创建一个字符串加法器,如果已经有一种紧凑的方法
// ... want to do equivalent of
// buff = dgdx + thisop + dhdx
那我想用那个工具。
您正在寻找的是字符串连接,标准 C 库函数是 strcat
,或更好(因为可以说更安全)strncat
。
您试图实现的目标无法在纯 C 中完成,因为它没有运算符重载。您可以为此使用 strncat
,但请注意,这是非常低级的解决方案,需要您手动管理内存。
您可以在 C++ 中使用 std::string
或 std::wstring
对象干净地完成此操作,这些对象具有适当的 operator+()
.
或者,您可以使用适当的面向对象的方式实现您自己的字符串结构 API。
如果您的 C 标准库是 GNU 或 *BSD,那么您可能 asprintf
可用。不过,您可能需要启用功能测试宏才能使用它。如果您没有 asprintf
可用,可以根据 C 标准 vsnprintf
函数轻松定义它。
asprintf
returns 格式的结果作为新分配的字符串(这是您对 free
的责任)。所以你可以写,例如:
char* buff;
int n = asprintf(&buff, "%s%c%s", dgdx, thisop, dhdx);
我通常使用包装函数,其中 returns 字符串而不是长度,所以你可以这样写:
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;
}
这是我所知道的与其他语言中的字符串连接运算符最简洁的等价物。 (它不一定是执行时间最高效的,但它可能是程序员时间。)
我正在制作一个函数,该函数 returns 表示为树状函数的导数
/ + \
* ^
/ \ / \
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;
如果一个节点没有children,例如上例中的x
、5
、3.14
,则其op
、gx
、hx
为NULL
,否则它的 fx
是 NULL
.
我计算导数的函数看起来像
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] = '[=12=]';
return buff;
}
但是我在所有的字符串添加上都被绊倒了。我可以从头开始创建一个字符串加法器,如果已经有一种紧凑的方法
// ... want to do equivalent of
// buff = dgdx + thisop + dhdx
那我想用那个工具。
您正在寻找的是字符串连接,标准 C 库函数是 strcat
,或更好(因为可以说更安全)strncat
。
您试图实现的目标无法在纯 C 中完成,因为它没有运算符重载。您可以为此使用 strncat
,但请注意,这是非常低级的解决方案,需要您手动管理内存。
您可以在 C++ 中使用 std::string
或 std::wstring
对象干净地完成此操作,这些对象具有适当的 operator+()
.
或者,您可以使用适当的面向对象的方式实现您自己的字符串结构 API。
如果您的 C 标准库是 GNU 或 *BSD,那么您可能 asprintf
可用。不过,您可能需要启用功能测试宏才能使用它。如果您没有 asprintf
可用,可以根据 C 标准 vsnprintf
函数轻松定义它。
asprintf
returns 格式的结果作为新分配的字符串(这是您对 free
的责任)。所以你可以写,例如:
char* buff;
int n = asprintf(&buff, "%s%c%s", dgdx, thisop, dhdx);
我通常使用包装函数,其中 returns 字符串而不是长度,所以你可以这样写:
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;
}
这是我所知道的与其他语言中的字符串连接运算符最简洁的等价物。 (它不一定是执行时间最高效的,但它可能是程序员时间。)