在 C 中获取字符串中的最后一个字符时,strlen 不安全吗?



有没有办法让我用strlen获取字符串中的最后一个字符?如果没有,我无法理解可以在什么上下文中使用 strlen。

char buf[256] = "Hello";
char * lastchar = buf[strlen(buf) - 1];

使用它安全吗?

如果你的字符串实际上是以 null 结尾的(否则它们实际上不是字符串!!(,是的,只要字符串中至少有一个字符(终止 null 除外(,它是安全的。

strlen()计算以 null 结尾的字符串(不包括 null 终止符(中的字节数。请记住,C 使用从 0 开始的索引。

所以"Hello"真的很'H', 'e', 'l', 'l', 'o', ''strlen("Hello")返回5,所以你正在访问buf[4]('o'(,这很好。如果您有空字符串,"" ,则没有倒数第二个字符,因此在这里使用它之前检查 strlen() 的返回值很重要。

一个警告:如果你想得到最后一个字符,你应该这样做

char lastchar = buf[strlen(buf) - 1];

如果你打算得到一个指向最后一个字符的指针,你应该这样做

char * lastchar = &buf[strlen(buf) - 1];
字符串

中的最后一个char始终为空字符。

char lastchar = buf[strlen(buf)];

string是由第一个空字符终止并包括第一个空字符的连续字符序列。 C11 §7.1.1


仅当字符串包含的字符数超过空字符时,获取字符串中的倒数第二个字符才是安全的。

size_t len = strlen(buf);
if (len > 0) {
  char secondtolastchar = buf[len-1];
}

请记住strlen(buf) - 1即使返回零,也永远不会是负数strlen()。 下面会发生什么?

char buf2[2] = "X";
char *buf = &buf2[1];
char ch = buf[strlen(buf) - 1];

buf采用 buf2[]strlen(buf) --> 0 中的空字符的地址。 所以看起来下一行代码可以buf[-1]希望是'X'. 相反,strlen()返回类型 size_t,它是一些无符号整数类型。 size_tint的减法肯定会导致size_t。 所以((size_t) 0) - 1最大的size_t值:SIZE_MAX而不是 -1。 因此,buf[SIZE_MAX]超出了buf2[]的范围,并且是未定义的行为。

因此,为了安全起见,任何像- 1这样的减法都需要考虑溢出的影响。 上面的代码用if (len > 0)解决了这个问题

假设您的字符串正确以 null 结尾(就像在您的示例中一样(,它是安全的。

是的。这是一个完全有效的用法,除了你必须做指针算术而不是索引:char * lastchar = buf + strlen(buf) - 1;(记住buf是一个指针(。另一种方法是使用 strchr() ,这可能更快:char * lastchar = strchr(buf, '');

strlen()的另一个用途是当您想要复制字符串并且需要知道要分配多少内存时:

char *copy = malloc(strlen(buf) + 1);
strcpy(copy, buf);

>strlen 对于空指针是不安全的。

char* str = (char*)NULL;
size_t len = strlen(str);  /* segmentation fault -- crash */

50年后,这仍然存在,等待着困住粗心的人。

幸运的是,有一个简单的补救措施。

#define strlen(S) ( (S==NULL) ? 0 : strlen(S) )

将停止 SEG 故障并按预期返回 0。

如果缓冲区包含保证的 0 字符和至少一个字符,则它是安全的。但这个条件可能不符合...在开发阶段,其他软件模块(确定缓冲区(中的错误,病毒攻击,....如果字符串 es 空,则访问位置 [-1] 在 C 语言中通常不是问题,但它返回未确定的结果。因此,这种结构过于简单和安全。一般来说,strlen是不安全的:想想一种情况,软件没有准备好,缓冲区没有填充,因为软件的这一部分有错误,缓冲区包含..AA AA..(例如(直到内存结束。然后 strlen(..( 运行很长时间,可能会崩溃(因为空指针或内存保护(,并且可能违反中断的周期时间。有一些更好的解决方案,但并没有真正标准化。您可以在 www.vishia.org/emc/html/Base/StringJc_en.html 和整个系统中找到我的解决方案 www.vishia.org/emc

最新更新