在没有缓冲区的情况下连接字符串
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()
,两者都需要缓冲区。
- 我需要一个需要一个字符串的函数,我希望得到接近 Python
str1 + str2
语法的东西
如果你真的想使用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 字符串文字。
有没有办法在不预先分配缓冲区的情况下连接字符串?
考虑以下几点:
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()
,两者都需要缓冲区。
- 我需要一个需要一个字符串的函数,我希望得到接近 Python
str1 + str2
语法的东西
如果你真的想使用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 字符串文字。