【问题标题】:best method to assign new string value to char array将新字符串值分配给 char 数组的最佳方法
【发布时间】:2020-06-21 18:43:29
【问题描述】:

我知道我必须使用 strcpy / strncpy 将新的字符串值分配给现有的 char 数组。最近看到很多这样的代码

char arr[128] = "\0";
sprintf(arr, "Hello World"); // only string constants no variable input
// or
sprintf(arr, "%s", "Hello World");

两种变体给出相同的结果。后一种变体有什么优势?

【问题讨论】:

  • 2 Q 在这里:“最佳方法.....”以及两种方法之间的差异。这里哪个问题更重要?
  • 很确定代码是由一个新手编写的,你不应该效仿他的例子。赠品是字符串"\0",它表明作者不了解字符串在 C 中的工作原理。

标签: c printf strcpy


【解决方案1】:

这取决于要复制的字符串是文字,如图所示,还是可以变化。

显示数组的最佳技术是:

char arr[128] = "Hello World";

如果您负责该字符串并且它不包含 % 符号,那么两个 sprintf() 调用之间没有太大区别。严格来说,第一个使用字符串作为格式并直接复制字符,而第二个注释它使用%s 作为格式并直接从额外参数中复制字符——它慢得多。有一个案例:

snprintf(arr, sizeof(arr), "%s", "Hello World");

即使“Hello World”变成更长的诽谤,也能确保缓冲区不会溢出。

如果您不负责字符串,那么使用如图所示的snprintf() 就变得很重要,因为即使字符串包含% 符号,它也会被简单地复制并且不会溢出。您必须检查返回值以确定是否有任何数据被截断。

如果您知道字符串有多长并且有空间容纳它,那么使用strcpy() 是合理的。使用strncpy() 很麻烦——如果源比目标短,它会空填充到全长,如果源对目标来说太长,它不会空终止。

如果您确定字符串的长度足够短,使用memmove()memcpy() 也是合理的。如果字符串太长,则必须选择错误处理策略——截断或错误。

如果目标数组中的尾随(未使用)空间必须为空字节(出于安全原因,以确保其中没有隐藏剩余密码),那么使用strncpy() 可能是明智的——但要注意确保空终止,如果源太长了。在大多数情况下,数组的初始化器并不是真正需要的。

编译器可能能够优化简单的情况。

【讨论】:

  • memcpy(dst, src, min(sizeof(dst), sizeof(src)); 对我来说似乎是最好的选择(很明显它在做什么)。不过,您可能需要处理 nul 终止。
  • 如果sizeof(src) 是可合理评估的,这是可行的——这取决于“Hello”来自世界的哪个地方——正如你提到的,你必须努力确保空终止。需要更多上下文才能给出更简洁的答案。
  • 您所说的“非常慢”是什么意思?它速度较慢,但​​您无法测量多少?它的速度非常慢?我认为它会稍微快一点,特别是如果字符串很长,但我实际上没有对 s(n)printf 实现进行基准测试,所以这只是我的偏见。
  • 性能差异可能很小,无法衡量,@rici。差异大致是扫描%s 并使用va_arg 弹出参数所花费的时间。不是完全为零,但接近于它,并且可能不是任何正常程序的整体性能的一个因素。使用%s 带来的安全性可能值得微小的性能损失。
  • @JonathanLeffler:我用 gcc 做了一个快速的工作台,正如预期的那样,%s 版本的参数非常大(可测量但差异很小)。我的假设是基于这样一个事实,如果你把字符串放在格式中,sprintf 必须将每个字符与百分比进行比较,而如果你把它作为字符串参数,它只需要检查 NUL。
【解决方案2】:

如果字符串包含任何% 字符,第一个版本将不起作用,因为sprintf() 会将它们视为需要使用附加参数填充的格式化运算符。这不是固定的问题像Hello World 这样的字符串,但如果你动态地获取字符串,它可能会导致未定义的行为,因为不会有任何参数来匹配格式化运算符。这可能会导致安全漏洞。

如果您实际上没有进行任何格式化,更好的方法是使用strcpy()

strcpy(arr, "Hello World");

此外,在初始化字符串时,不必在字符串中添加显式\0。字符串文字总是以空字节结尾。所以你可以将它初始化为:

char arr[128] = "";

如果您立即用sprintf()strcpy() 覆盖变量,则不需要首先对其进行初始化。

【讨论】:

  • 也许值得注意的是,在某些情况下没有格式字符串是一个安全漏洞。如果要打印的字符串是从输入中接收的,那么当用作格式字符串时,可以利用它来访问甚至修改(使用%n)内存。
猜你喜欢
  • 2012-10-16
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 2011-02-07
  • 1970-01-01
  • 2014-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多