在没有缓冲区的情况下连接字符串

Concatenating strings without buffers

有没有办法在不预先分配缓冲区的情况下连接字符串?

考虑以下几点:

int main()
{
    char buf1[] = "world!";
    char buf2[100] = "hello ";
    char * p = "hello ";
    // printf("%s", strcat(p, buf1)); // UB
    printf("%s", strcat(buf2, buf1)); // correct way to use strcat
    return 0;
}

如果我有一个指针想要作为字符串的前缀,是否必须先将其复制到缓冲区然后 strcat()?是否有任何函数可以隐式执行此操作?

我想到的唯一选项是 strcat()sprintf(),两者都需要缓冲区。

如果你真的想使用C,那么你需要使用缓冲区。在 C++ 或 Python 中,您可以使用将为您隐藏工作的构造函数和运算符,但在 C 中,您必须自己做一些事情。如果你想让你的代码更简单,你可以创建一个小的辅助函数,但要注意内存泄漏和线程:

#include "stdlib.h"
#include "string.h"
#include "stdio.h"

const char * strconcat(const char *p1, const char *p2)
{
    static __thread char buffer[2048];
    snprintf(buffer, 2048, "%s%s", p1, p2);
    return buffer;
}

int main(int argc, char** argv)
{
    const char *p1 = "hello ";
    const char *p2 = "world!";
    printf("%s\n", strconcat(p1, p2));
}

只要生成的字符串不超过 2048 个字符,此示例就可以运行;否则生成的字符串将被截断。

这当然只是您可以创建的辅助函数的一个示例。

请注意,上面的示例 returns 是您无法编辑的 const char *。如果你想进一步编辑字符串,你需要创建一个分配缓冲区的辅助函数,但是你需要管理你的内存!

好吧,它不是标准的 C,所以不是很便携,但是在 GNU libc 系统上你可以使用 asprintf()

int main(void)
{
    const char buf1[] = "world!";
    const char * const p = "hello ";
    char *s;
    if (asprintf(&s, "%s%s", p, buf1) > 0 && s != NULL)
    {
      puts(s);
      free(s);
    }
    return 0;
}

在兼容系统上编译并 运行 时,会打印

hello world!

在 run-time 中执行此操作的最有效方法是调用 malloc 并为新字符串分配空间,然后将所有内容复制到那里。这很可能是 Python 在行后所做的 - 尽管它将具有字符串类型。

在 ADT/class 之外执行此操作的缺点是您必须手动执行 clean-up。

然而,使用 malloc + copy 比任何 *printf 都快得多,它是线程安全的,同样的功能可以再次 re-used。示例:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* strdog (const char* s1, const char* s2)
{
  size_t size1 = strlen(s1);
  size_t size2 = strlen(s2);
  char* result = malloc(size1 + size2 + 1);
  if(result == NULL) 
  {
    exit(EXIT_FAILURE);
  }

  memcpy(result, s1, size1);
  memcpy(result+size1, s2, size2);
  result[size1 + size2] = '[=10=]';
  return result;
}

inline void cleandog (char* s)
{
  free(s);
}

int main (void)
{
  char s1[] = "hello ";
  char s2[] = "world";

  char* str = strdog(s1, s2);
  puts(str);
  cleandog(str);
}

但是请注意,C 支持 compile-time 串联。所以如果你只使用字符串文字,你应该这样做:

#define HELLO "hello "
#define WORLD "world"

...

const char* str = HELLO WORLD;
puts(str);

这当然是它们的高级版本,但只适用于 compile-time 字符串文字。