【问题标题】:Quick strlen question快速提问
【发布时间】:2011-02-11 17:06:15
【问题描述】:

我是来用另一个可能非常简单的 C 问题来打扰大家的。

使用以下代码:

int get_len(char *string){

    printf("len: %lu\n", strlen(string));

    return 0;
}

int main(){

    char *x = "test";
    char y[4] = {'t','e','s','t'};

    get_len(x); // len: 4
    get_len(y); // len: 6

    return 0;
}

2 个问题。为什么它们不同,为什么 y 是 6?谢谢大家。

编辑:对不起,我知道什么会解决它,我只是想了解发生了什么。那么 strlen 是否只是继续转发该点,直到它碰巧找到 \0?另外,当我在 main 函数中而不是在 get_len 函数中执行 strlen 时,两者都是 4。这只是巧合吗?

【问题讨论】:

  • 是的,这只是巧合。
  • 作为答案的旁白(如果有点重复,那就太好了)我要指出,虽然"test" 是序列't','e','s','t',0 的一种方便语法,但实际上你可以作为一个特殊的case 用 char y[4]="test"; 初始化一个 char 数组,在这种情况下,最后的 0 将被省略(在 y 中根本没有空间)。

标签: c string strlen


【解决方案1】:

当你使用单引号时总是使用'​​/0',但在双引号中避免在strlen()中使用'/0'

注意 strlen() 函数在计算长度时不计算空字符 \0

【讨论】:

    【解决方案2】:

    正如其他人所说,您只需要确保以 0 或 '\0' 字符结尾的字符串。作为旁注,您可以查看:http://bstring.sourceforge.net/。它具有 O(1) 字符串长度函数,不像 C/C++ strlen 容易出错并且在 O(N) 时速度很慢,其中 N 是非空字符的数量。我不记得上次使用 strlen 和它的朋友是什么时候。选择安全快速的函数/类!

    【讨论】:

      【解决方案3】:

      y 不是以空值结尾的。 strlen() 对字符进行计数,直到遇到空字符。你碰巧在 6 之后找到了一个,但它可以是任何数字。试试这个:

      char y[] = {'t','e','s','t', '\0'};

      这是strlen() 的实现可能看起来的样子(在我的脑海中——手边没有我的 K&R 书,但我相信那里有一个实现):

      size_t strlen(const char* s)
      {
          size_t result = 0;
          while (*s++) ++result;
          return result;
      }
      

      【讨论】:

      • 那么 strlen 是否只是转发指针,直到它在任何可能的地方找到一些 \0 ?
      • @LearningC:没错。它不断增加指针并查看那里的内容。当它找到一个零时,它会停止并返回它查看了多少个字符(不包括零)。
      • @LearningC:是的。或者直到它因段错误而崩溃。或者直到它格式化您的硬盘驱动器。如果您的输入不是以零结尾的,则行为是 undefined任何事情都可能发生。
      • AndreyT 是正确的。在实践中,它通常会在任何不好的事情发生之前找到一个空值。但你永远无法确定。我怀疑它是否真的会格式化你的硬盘,但你肯定会进入禁止的内存并出现分段错误。
      • @LearningC:终止字符串是函数调用者的要求,就像 strlenstrcpy 的调用者要求输入是以 nul 结尾的字符串。
      【解决方案4】:

      这个

      char y[4] = {'t','e','s','t'};
      

      不是一个正确的以零结尾的字符串。这是一个由四个字符组成的数组,没有终止符'\0'strlen() 只是简单地计算字符,直到它达到零。使用y,它只会在数组末尾计数,直到意外找到零字节。
      这样做是在调用未定义的行为。该代码也可以格式化您的硬盘驱动器。

      您可以通过使用字符数组初始化的特殊语法来避免这种情况:

      char y[] = "test";
      

      这会使用 五个 个字符初始化 y,因为它会自动附加一个 '\0'
      请注意,我还没有指定数组的大小。编译器自己计算出来,如果我改变字符串的长度,它会自动重新计算。

      顺便说一句,这是一个简单的strlen() 实现:

      size_t strlen(const char* p)
      {
          size_t result = 0;
          while(*p++) ++result;
          return result;
      }
      

      现代实现可能不会获取单个字节,甚至不会使用 CPU 内在函数,但这是基本算法。

      【讨论】:

      • 哇,在添加我的之前,我没有看到你的strlen()。他们一模一样!伟大的思想...... 8v)
      • 字符串函数的 GNU libc 源代码非常有启发性,而且非常复杂。
      • @Fred:嗯,它是 C 库中最基本的算法之一,也是 K&R 中的一个典型例子。难怪我们大多数人都将它铭刻在他们的记忆中。
      【解决方案5】:

      您需要以空值终止 y。

      int get_len(char *string){
      
          printf("len: %lu\n", strlen(string));
      
          return 0;
      }
      
      int main(){
      
          char *x = "test";
          char y[5] = {'t','e','s','t','\0'};
      
          get_len(x); // len: 4
          get_len(y); // len: 4
      
          return 0;
      }
      

      strlen() 基本上获取您给它的指针并计算字节数,直到内存中的下一个 NULL。碰巧在你的记忆中后面有两个字节的NULL。

      【讨论】:

      • 那么 strlen 是否只是转发指针,直到它在任何可能的地方找到一些 \0 ?
      • 这有两个问题。首先,NULL 旨在作为空指针,而不是空字符。其次,你还有char y[4],所以你有一个额外的初始化器。您需要五个位置才能拥有一个“测试”字符串。
      • 对不起,忘了增加索引,但我不知道 NULL 的事情。每天学习新东西。
      【解决方案6】:

      一个实际的 C 类型字符串比它的字符数大一,因为它需要一个终止空字符。

      因此,char y[4] = {'t','e','s','t'}; 不会形成字符串,因为它是四个字符。 char y[] = "test";char y[5] = "test"; 将形成一个字符串,因为它们有一个以空字节终止符结尾的五个字符的字符数组。

      【讨论】:

        【解决方案7】:

        strlen字符串 一起使用。字符串定义为以\0 字符结尾的字符序列(数组)。

        您的x 指向一个字符串。因此,strlenx 作为参数可以正常工作。

        您的y 不是字符串。因此,将y 传递给strlen 会导致未定义的行为。结果是毫无意义且不可预测的。

        【讨论】:

          【解决方案8】:
          char y[5] = {'t','e','s','t','\0'};
          

          一样
          char *x = "test"; 
          

          【讨论】:

          • 对于strlen(),是的。但是y是一个由五个char组成的数组,其内容可以随意修改。 x 是指向char 的指针,在这种情况下,它指向一个无法可靠修改的字符串。另一方面,可以将值重新分配给x,但不能重新分配给y
          • @David Thornley 答案是在初学者上下文中给出的,只是为了说明根据 OP 出了什么问题。现在给出了更好的答案。无需投票
          • IME 和这个一样细微的差异(x[0]='x'; 在你说 char x[]="X"; 时很好,但在你说 char* x="X"; 时很致命)永远不能过分强调,尤其是对于初学者。
          【解决方案9】:

          以下不是以空字符结尾的字符数组:

           char y[4] = {'t','e','s','t'};
          

          strlen() 的部分合同是为它提供一个指向空终止字符串的指针。由于strlen(y) 不会发生这种情况,因此您会得到未定义的行为。在您的特定情况下,您会收到 6 返回,但任何事情都可能发生,包括程序崩溃。

          来自 C99 的 7.1.1 “术语定义”:

          string 是一个连续的字符序列,以第一个 null 结尾,包括第一个 null 字符。

          【讨论】:

            猜你喜欢
            • 2011-03-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-11-09
            相关资源
            最近更新 更多