【问题标题】:How to concatenate strings formatted with sprintf in C如何在C中连接用sprintf格式化的字符串
【发布时间】:2021-10-03 09:37:53
【问题描述】:

我有多个句子目前正在控制台中打印。我必须将它们收集成一个字符串。

部分代码为:

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

int main()
{
    char buffer [100];
    sprintf (buffer, "%d plus %d is %d", 5, 3, 5+3);
    char *c=buffer;
    sprintf (buffer, "and %d minus %d is %d", 6, 3, 6-3);
    strcat(c, buffer);
    printf ("[%s]",c);
    return 0;
    return 0;
}

我尝试使用 sprintf 创建格式化字符串,但结果错误。句子的长度和数量不受限制。

我希望上面代码的输出是这样的:

[5 加 3 为 8,6 减 3 为 3]

但它是:

[6 减 3 是 3,6 减 3 是 3]

我需要如何连接它们?此外,句子的长度和数量是无限的。我在使用 malloc 和 realloc 时遇到困难。有人可以帮忙吗?

【问题讨论】:

  • 当你可以直接打印缓冲区时,使用char指针并将缓冲区数组分配给它的目的是什么?
  • 将数组的地址分配给指针不会复制内容。
  • 对于malloc() 和朋友,请发布另一个问题。这是一个不相关的问题。
  • 当我不使用char指针直接打印缓冲区时,只存储和打印最后一个spritnf中的字符串。
  • 使用两个缓冲区,连接它们并打印它们,而不是使用指针。

标签: c string-concatenation strcpy formatted


【解决方案1】:

sprintf (buffer, "and %d minus %d is %d", 6, 3, 6-3); 重写 buffer 而不是连接。之前sprintf()的原始结果丢失了。

strcat(c, buffer);buffer 附加到自身。由于重叠,它是未定义的行为(UB)。不要那样做。


改为使用sprintf()(打印字符数)的返回值来确定胶印。

int offset = sprintf (buffer, "%d plus %d is %d", 5, 3, 5+3);
offset += sprintf (buffer + offset, " and %d minus %d is %d", 6, 3, 6-3);
offset += sprintf (buffer + offset, " even more");
printf ("[%s]",buffer);

避免使用strcat(),因为这需要代码向下迭代先前的字符串,从而导致Schlemiel the Painter's Algorithm。最好跟踪字符串长度并将其用于下一个sprintf()


更好的代码可以使用snprintf() 来防止缓冲区溢出。

// Pedantic example
char buffer [100];
size_t offset = 0;
size_t available = sizeof buffer;

int retval = snprintf (buffer, available, "%d plus %d is %d", 5, 3, 5+3);
if (retval < 0 || (unsigned) retval >= available) Handle_Overflow();
offset += retval;
available -= retval;

retval = snprintf (buffer + offset, available, " and %d minus %d is %d", 6, 3, 6-3);
if (retval < 0 || (unsigned) retval >= available) Handle_Overflow();
offset += retval;
available -= retval;

retval = snprintf (buffer + offset, available, " even more");
if (retval < 0 || (unsigned) retval >= available) Handle_Overflow();
offset += retval;
available -= retval;

printf ("[%s]",buffer);

句子的长度和数量不受限制。

通常较大的缓冲区就足够了,因为 unlimited 并不是真正的 unlimited,只是可能很大。 C 字符串仅限于SIZE_MAX

替代方案:研究非C标准asprintf()

【讨论】:

  • 当然要注意检查offset 加上字符串文字和转换的预期长度不超过缓冲区大小(减1)。 (当我啄食时你得到了它......)
  • @DavidC.Rankin True,因此“更好的代码可以使用 snprintf()”部分的答案。我会为 OP 详细说明,但想先解决非strcat() 解决方案。
  • 如果你足够大,你会记得一个情景喜剧,他的介绍使用了 "Schlemiel" 两种不同的发音,并提到了“Hasenpfeffer Incorporated”:)
  • @DavidC.Rankin Surely 你不能是认真的 - 和stop calling me Shirley。 ;-)
【解决方案2】:

好的程序需要好的设计。简化它。

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

int main()
{
    fprintf(stdout, "%d plus %d is %d", 5, 3, 5+3);
    fprintf (stdout, "and %d minus %d is %d", 6, 3, 6-3);
    return 0;
}

为了处理unlimited问题,可以输出到文件或者其他。

【讨论】:

  • 这个答案有点像告诉想学游泳的人应该去跑步。学习如何在缓冲区中移动数据,并准确了解放置数据的数量和位置是 C 语言中非常有价值的技能。回避这个问题并不能教会如何解决这个问题。
  • 你觉得他需要通过这个问题学习'malloc'还是'realloc'?
  • 这当然是一种选择,而不是明确的答案,但它可以提供有关解决问题的不同方法的见解。 chux 的答案有一个在堆栈分配的缓冲区上维护边界和偏移量的示例,也许您可​​以向我们展示如何使用动态分配的内存来解决这个问题?无论哪种方式,您当前的答案都是对一个完全不同的问题的答案(即如何打印插值数据?),与字符串连接无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
相关资源
最近更新 更多