【问题标题】:strlen function always returning 0strlen 函数总是返回 0
【发布时间】:2014-09-03 18:05:55
【问题描述】:

对于家庭作业,我们必须编写一个简短的程序,使用 argc 和 argv 告诉您传递给 main 的参数数量、它们的数据地址以及每个参数是什么。我们还必须编写一个名为 strlen 的函数(我们不允许使用库中包含的任何类似函数),该函数使用指针计算传递给 main 的每个参数的长度。我的函数总是返回 0。很抱歉我问了这么一个基本问题,但作为一年级学生,我还没有接受过调试器使用方面的培训。这是我的代码:

int strlen(char * p)
{
    char X[50];
    p = &X[0];
    int i = 0;

    while (*(p + i) != '\0')
       i++;

    return i;
}

我已经尝试了几种不同的方法来解决这个问题,但无论函数如何似乎总是返回值 0。我忽略了一个明显的巨大问题吗?任何朝着正确方向的推动都会有所帮助,但请不要只给我答案。

【问题讨论】:

  • 您将&X[0] 的值分配给 p 这里 -- p = &X[0];
  • “请不要只给我答案”——试试Rubber Duck Debugging。向鸭子解释X 应该做什么。
  • 如果您对char X[50];p = &X[0]; 没有任何理由,您可以直接删除这些行。
  • 您知道char X[50] 有不确定的内容吗?您永远不会检查传入 char *p 引用的数据的长度,而是通过使用本地自动(且不必要的)数组的地址覆盖传入地址而立即丢失它。并且为了保持一致性,char* p 应该是 const char *p 并且函数应该返回 size_t,而不是 int
  • 保留名称strlen。使用该名称编写您自己的函数可能会导致意外行为。例如,对strlen 的调用可以调用您的函数或标准函数。使用不同的名称,例如 my_strlen

标签: c++ arrays string pointers


【解决方案1】:

您编写了一个函数来计算本地“字符串”X 的长度。数组X 甚至没有被初始化。它包含垃圾。您的函数返回该垃圾字符串的长度。不一定是0,只是在你的实验中偶然碰巧为零。在一般情况下,您的函数将返回一个垃圾值或只是导致您的程序崩溃。行为未定义。

换句话说,当您将函数调用为strlen("hello") 时,您编写的代码会完全忽略"hello" 字符串。您的函数仍然坚持使用本地数组 X,而不是使用从外部传递的参数字符串 "hello"

如果是你写了这个函数,那真的是一个问题:你为什么要那样做?

附: strlen 的更明智的实现可能会接收const char * 参数(不是char *)并在size_t 类型的域中执行计数(不是int)。

附言*(p + i) 等价于 p[i]。许多人会发现后者比前者更具可读性。

【讨论】:

  • 谢谢!我知道这是显而易见的事情,但我忽略了它。我的程序现在按预期运行。
【解决方案2】:

首先,你的函数没有意义;它覆盖参数并且数组 X 未初始化,因此其元素具有一些未指定的值,并且使用此函数的程序具有未定义的行为。 该函数可能如下所示:

size_t strlen( const char * p )
{
    size_t i = 0;

    while  ( *( p + i ) != '\0' ) i++;

    return i;
}

或更具可读性

size_t strlen( const char * p )
{
    size_t i = 0;

    while  ( p[i] != '\0' ) i++;

    return i;
}

例如

#include <iostream>

size_t strlen( const char * p )
{
    size_t i = 0;

    while  ( p[i] != '\0' ) i++;

    return i;
}

int main()
{
   char s[] = "Hello gsoble";

   std::cout << "The size of the greeting is " << strlen( s ) << std::endl;
}

【讨论】:

    【解决方案3】:

    只需去掉前两行。

    int strlen(char * p)
    {
        int i = 0;
        while (*(p + i) != '\0')
            i++;
    
        return i;
    }
    

    工作示例:http://ideone.com/8R8Elu

    【讨论】:

      【解决方案4】:

      正如其他答案所解释的,您在此处将 p 设置为等于未初始化的 x,这会给您带来未定义的行为。然而,其他答案没有给你的是.....递归(因为为什么不)

      unsigned strlen(const char *p) {
          if(*p == '\0') return 0;
          return 1 + strlen(p+1);
      }
      

      如果你想把它减少到 1 行:

      unsigned strlen(const char *p) {
          return (*p == '\0') ? 0 : 1 + strlen(p+1);
      }
      

      【讨论】:

        【解决方案5】:

        这是未定义的行为。您将X 数组传递到'\0',但'\0' 可能永远不会发生,因为X 是具有未定义值的本地对象。相反,您可能会遇到分段错误。

        我是否忽略了一个非常大的问题?

        您不需要本地数组。你可以从

        开始
        size_t strlen( const char * p) // take const for safety reasons
        {                              // and return size_t for compatibility
            size_t i = 0;
            while ( *(p + i) != '\0') ++i;
        
            return i;
        }
        

        【讨论】:

        • @BenVoigt:strlen(X) 在问题的代码中是预期的——但X 不是函数应该查看的内容,实际上X 不是必需的完全没有。
        猜你喜欢
        • 2016-07-21
        • 2011-08-27
        • 2018-09-26
        • 2012-12-02
        • 1970-01-01
        • 2022-01-14
        • 2012-08-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多