【问题标题】:How to use strchr() multiple times to find the nth occurrence如何多次使用 strchr() 来查找第 n 次出现
【发布时间】:2017-09-06 08:30:48
【问题描述】:

我正在尝试找到一种方法来完成这项工作:

//Returns a pointer to the nth char in a string
const char *nth_strchr(const char *s, int c, int n) {
    int c_count = 0;
    char *nth_ptr;

    while (c_count++ != n) {
        nth_ptr = strchr(s, c);
        //need a line here to skip past the previous found occurrence.
    }
    return nth_ptr;
}

我不太确定如何做到这一点,以便while 循环的每次迭代都可以确认在前一个循环中找到的字符的出现/位置。因为我有指向第一次出现的指针......我正在考虑使用内存地址来增加下一个循环,以便我可以给下一个 strchr() 调用从 c + 1 位置开始的字符串? 这可能吗?

【问题讨论】:

  • if (nth_ptr==NULL) break; else nth_ptr++;
  • strchr 返回什么?指向它在字符串中找到的字符的指针(如果未找到,则为 NULL)。现在想一想如何使用它来获取字符串中的下一个字符。

标签: c string


【解决方案1】:
const char* nth_strchr(const char* s, int c, int n)
{
    int c_count;
    char* nth_ptr;

    for (c_count=1,nth_ptr=strchr(s,c); 
         nth_ptr != NULL && c_count < n && c!=0; 
         c_count++) 
    {
         nth_ptr = strchr(nth_ptr+1, c);
    }

    return nth_ptr;
}

此代码已经过测试。

【讨论】:

  • 虽然这段代码很简洁,但它降低了可读性。使用编程语言的花哨功能来减少代码行数不一定是好事。
  • @HansPetterTaugbølKragset 我在 Linux 和 MS Visual Studio 的源代码中看到了这种代码风格。对我来说,这种代码风格还可以。如果我将使用另一种代码样式编辑项目,我将使用另一种代码样式(项目接受的样式)。但是这里只是普通库函数的扩展,所以恕我直言,这种风格是可以接受的。
  • 我明白你在说什么,但我不同意。在这种情况下,读者可能是想学习 C 的新手,而您提供的代码不一定是最擅长教学的。当然它是正确的,但它是不必要的复杂恕我直言。
【解决方案2】:

显而易见的 (?) 方式当然是使用 strchr() 的返回值作为新字符串,在添加 1 以跳过已知存在的事件之后,是的。

类似:

const char * nth_strchr(const char *s, int c, int n)
{
  for (;;)
  {
    if (n <= 0)
      return NULL;
    const char *h = strchr(s, c);
    if(h == NULL)
      return NULL;
    if (--n == 0)
      return h;
    s = h + 1;
  }
  return NULL;
}

【讨论】:

    【解决方案3】:

    假设您在字符串scnth 出现之后,而不是您评论中所说的nth 字符,那么这一行

    s = nth_ptr + 1;
    

    在循环结束时,您的 s 指针会在 c_countth 在 s 中出现 c 之后指向字符。

    请记住还要检查来自strchr 的返回值,如上面的 cmets 中所述。

    【讨论】:

      【解决方案4】:

      我认为代码可以像这样简单,如果字符串 s 中没有出现 n 字符 c 时,使用计数 (for) 循环并提前转义:

      const char *nth_strchr(const char *s, int c, int n) 
      {
          const char *nth = s;
          assert(c != '\0');
      
          for (int i = 0; i < n; i++)
          {
              if ((nth = strchr(nth, c)) == 0)
                  break;
              nth++;
          }
      
          return nth;
      }
      

      break; 可以替换为 return 0;return NULL;。条件可以是== NULL 而不是== 0。我假设至少 C99;如果您没有可用的,那么您需要在循环外定义i

      断言是最迂腐的。如果没有详细了解代码将如何使用,并且没有使其成为合理选择的上下文,您就无法将指针递增到第一个 null 之外。

      其他答案也有类似的净效应,但 IMO 代码没有写得那么清楚(这就是为什么我在这么晚才添加答案的原因)。将循环的控件分布在三行上并在设置中使用多个分配使其比需要的更难阅读。在调用计数循环时使用无限循环似乎是一种混淆。

      【讨论】:

        【解决方案5】:

        在您的代码中,您一直在查找第一次出现的c,如果nth_ptr 不是NULL,您应该添加s = nth_ptr + 1;,但您应该为n == 0 和/或c == '\0' 设置特殊情况.

        这是一个更简单的版本:

        const char *nth_strchr(const char *s, int c, int n) {
            if (c == '\0' && n > 1)  /* special case the null terminator */
                return NULL;
            if (n > 0) {
                while ((s = strchr(s, c)) != NULL && --n > 0) {
                    s++;
                }
            }
            return s;
        }
        

        【讨论】:

        • 你忘记了右括号。
        【解决方案6】:

        //试试这个程序

        #include<stdio.h>
        #include<string.h>
        int main()
        {
        char *q,arr[]="This is strchr i program";
        int i=0;
        while((q=strchr(arr+i,'i'))!=NULL){
            printf("%s\n",q);
            i=(char *)q-(char *)arr;
            i=i+1;
        }
        return 0;
        }
        

        【讨论】:

        • 也许添加一个关于你改进了什么的解释?
        猜你喜欢
        • 1970-01-01
        • 2015-12-04
        • 1970-01-01
        • 1970-01-01
        • 2014-03-10
        • 2016-01-16
        • 2013-09-26
        • 2011-02-04
        • 2020-03-16
        相关资源
        最近更新 更多