【问题标题】:How to write your own strchr in c using pointers?如何使用指针在 c 中编写自己的 strchr?
【发布时间】:2017-06-11 08:19:05
【问题描述】:

好的,我的教授给我一个任务。这里是:


编写一个名为 strchr406 的函数。它传递了 2 个参数:一个字符串和一个字符 下面是函数的原型: char *strchr406(char str[], char ch); 该函数应返回指向 str 中第一个 ch 实例的指针。例如:

char s[ ] = "abcbc";
strchr406(s, 'b');   // returns s + 1 (i.e., a pointer to the first 'b' in s)
strchr406(s, 'c');   // returns s + 2
strchr406(s, 'd');   // returns 0

他要求我们使用指针编写我们自己的 strchr 版本。我在网上查找资源,但没有一个符合他要求我们做的事情。我正在和一群其他学生一起工作,我们谁也想不通。

我们如何返回“s + 1”?

到目前为止,我有这个: (如果方便的话,我也把它放到网上:https://repl.it/FVK8

#include <stdio.h>
#include "string_problems.h"

int main() {
  char s[ ] = "abcbc";
  strchr406(s, 'b');   // returns s + 1 (i.e., a pointer to the first 'b' in s)
  strchr406(s, 'c');   // returns s + 2
  strchr406(s, 'd');   // returns 0
  printf("this should return %s\n", strchr406(s, 'c'));
  return 0;
}

char *strchr406(char str[], char ch) {
  char *p = str;
  int index = 0;
  while (*str != ch) {
    ++str;
    ++index;
  }
  if (*str == ch) {
    return p + index;
  } else {
    return 0;
  }

}

我得到了奇怪的输出。任何帮助表示赞赏。

【问题讨论】:

  • 不清楚你的问题是什么。 strchr 是一个非常简单的函数。但是,您不能从函数中返回指针或整数,因为给定的赋值是无意义的(并且教导使用 0 作为空指针常量是不好的风格;使用 NULL 宏)。也许你的教授的意思是一个空指针,它和整数0不一样?但是你不能像字符串一样打印它,而是显式测试并打印不同的东西(这就是空指针的想法)。
  • 不要发布文字图片。您至少应该将其粘贴为文本。
  • 我现在编辑一下。
  • 是的,我不确定他在这里问什么。我不知道“s+1”和“s+2”在这里是如何工作的。
  • 发布的代码使用了一个头文件:stringproblems.h,但该文件的内容没有发布。您希望我们猜测该文件的内容吗?

标签: c string pointers strchr


【解决方案1】:

来自手册:

  • char *strchr(const char *s, int c); --> 第二个参数是一个整数
  • strchr() 和 strrchr() 函数返回一个指向匹配字符的指针,如果找不到该字符,则返回 NULL。
  • 终止的空字节被认为是字符串的一部分, 因此,如果 c 被指定为 '\0',这些函数将返回一个指向终止符的指针。
  • [如果第一个参数恰好为 NULL,则没有定义的行为]

char *strchr42(char *str, int ch)
{
for (;; str++) {
        if (*str == ch) return str;
        if (!*str) return NULL;
        }
return NULL;
}

甚至更短:


char *strchr42a(char *str, int ch)
{
do      {
        if (*str == ch) return str;
        } while (*str++) ;
return NULL;
}

【讨论】:

    【解决方案2】:

    你来了

    #include <stdio.h>
    
    char * strchr406( const char str[], char ch ) 
    {
        while ( *str && *str != ch ) ++str;
    
        return ( char * )( ch == *str ? str : NULL );  
    }
    
    int main(void) 
    {
        char s[ ] = "abcbc";
    
        printf( "strchr406(s, 'b') == s + 1 is %d\n", strchr406(s, 'b') == s + 1 );
        printf( "strchr406(s, 'c') == s + 2 is %d\n", strchr406(s, 'c') == s + 2 );
        printf( "strchr406(s, 'd') == 0 is %d\n", strchr406(s, 'd') == 0 );
        printf( "this should return %s\n", strchr406(s, 'c'));
    
        return 0;
    }
    

    程序输出是

    strchr406(s, 'b') == s + 1 is 1
    strchr406(s, 'c') == s + 2 is 1
    strchr406(s, 'd') == 0 is 1
    this should return cbc
    

    告诉你的教授,这样声明函数是正确的

    char * strchr406( const char str[], char ch );
                      ^^^^^ 
    

    此外,标准函数具有以下声明

    char *strchr(const char *s, int c);
    

    因为 C 中的字符文字具有 int 类型。 所以你甚至可以通过以下方式编写函数

    char * strchr406( const char str[], int ch ) 
    {
        unsigned char c = ch;
    
        while ( *str && ( unsigned char )*str != c ) ++str;
    
        return ( char * )( c == ( unsigned char )*str ? str : NULL );  
    }
    

    至于你的函数,那么使用变量index 是没有意义的,因为指针str 本身会增加。

    【讨论】:

    • 告诉你的教授 strchr() 的第二个参数的类型是int,而不是char
    • 是的,我来自其他语言,但指针仍然存在一些问题。顺便说一句,您的打印语句实际上在做什么?我的意思是 strchr406(s, 'b') 如何等于 (s+1) ?
    • @nastypluto C 中的比较结果具有 int 类型。因此,例如,如果两个指针彼此相等,则它们的比较结果将等于 1。在此语句中 printf("strchr406(s, 'b') == s + 1 is %d\n", strchr406( s, 'b') == s + 1 );我证明返回的指针确实等于 s + 1。
    • 嗯,第二个想法,我似乎对 (unsigned char) 位有误。规范说“strchr 函数在 s 指向的字符串中定位int c(转换为char)的第一次出现。”所以*str != (char) ch 是正确的。对于unsigned char 的误导,我们深表歉意。
    • @chux 与 "3 比较 对于本小节中的所有函数,每个字符都应被解释为具有无符号字符类型":)
    【解决方案3】:

    您应该在代码中添加或重新组织一些小东西以使其正常工作。

    首先,这段代码

      while (*str != ch) {
        ++str;
        ++index;
      }
    

    不会在你的字符串末尾停止,而是继续循环,直到它在进程的虚拟内存中的字符串后面的某个地方找到你的字符。

    所以你可能应该有一个停止检查字符串结尾的条件(C 中的字符串以字符 \0 结尾,ASCII 码 = 0):

    while (*str != '\0')
    

    第二件事,您将ch 与循环后字符串的当前字符进行比较。您可能应该将此代码移动到循环中:您需要根据ch 检查字符串的每个字符。此外,您不需要同时使用索引并增加指针str。所以你可以摆脱index 变量。如果您在循环中的任何时候找到正确的ch,那么您可以使用str 直接返回指向它的指针。如果您退出循环,则意味着您没有在str 中找到ch,然后您可以返回NULL(有关返回值的更多信息,请参见man strchr)。

    char *strchr406(char str[], char ch)
    {
         while (*str != '\0')
         {
              if (*str == ch)
              {
                   return (str);
              }
              str++;
         }
         return (NULL);
    }
    

    请注意,在这种情况下,即使NULL0,最好使用NULL,因为您应该返回一个指针。

    最后一件事,如果你想完全像strchr 那样做,那么如果ch'\0',你应该在字符串str 的末尾返回指向'\0' 的指针。来自男人:The terminating null byte is considered part of the string, so that if c is specified as '\0', these functions return a pointer to the terminator。所以你的代码变成了:

    char *strchr406(char str[], char ch)
    {
         while (*str != '\0')
         {
              if (*str == ch)
              {
                   return (str);
              }
              str++;
         }
         /**                                                                                                                    
          * if ch is '\0', you should return                                                                                    
          * the pointer to the `\0` of the string str                                                                           
          */                                                                                                                    
         if (*str == ch)                                                                                                        
         {                                                                                                                      
              return (str);
         }
         return (NULL);
    }
    

    注意:感谢@chux 指出最后一件事。

    注意 2:在这种情况下,您无需检查 str 是否为 NULL

    注意 3:strchr 的“官方”原型是 char *strchr(const char *s, int c);,因此根据您的项目要求,您可能需要更新原型以匹配此原型。

    【讨论】:

    • 注意:return 不是一个函数。 return (NULL); -->> return NULL;
    • "请注意,在这种情况下,即使 NULL 为 0" - 错误,这对于许多实现来说都是错误的。通常NULL (void *)0。即使对于特定实现它是 0,您也不能也不应该依赖它。
    • 谢谢@wildplasser。是的 return 不是一个函数,但这是我使用的 C 风格:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2014-12-21
    相关资源
    最近更新 更多