strchr的实施是如何工作的

strchr的实施是如何工作的,c,pointers,constants,strchr,C,Pointers,Constants,Strchr,我试图编写自己的strchr()方法实现 现在看起来是这样的: char *mystrchr(const char *s, int c) { while (*s != (char) c) { if (!*s++) { return NULL; } } return (char *)s; } 最后一行原来是 return s; 但这不起作用,因为s是常量。我发现需要这个cast(char*),但我真的不知道我在那里

我试图编写自己的strchr()方法实现

现在看起来是这样的:

char *mystrchr(const char *s, int c) {
    while (*s != (char) c) {
        if (!*s++) {
            return NULL;
        }
    }
    return (char *)s;
}
最后一行原来是

return s;

但这不起作用,因为s是常量。我发现需要这个cast(char*),但我真的不知道我在那里做什么:(有人能解释一下吗?

const关键字意味着参数不能修改

您无法直接返回
s
,因为
s
声明为
const char*s
,函数的返回类型为
char*
。如果编译器允许您这样做,则可以重写
const
限制

将显式强制转换添加到
char*
会告诉编译器您知道自己在做什么(尽管正如Eric所解释的,如果不这样做会更好)

更新:出于上下文考虑,我引用Eric的答案,因为他似乎已经删除了:

您不应该修改s,因为它是常量字符*

相反,定义一个表示char*类型结果的局部变量,并在方法体中用它代替s

函数返回值应该是指向字符的常量指针:

strchr
接受一个
const char*
并且应该返回
const char*
。您返回的是一个非常量,因为返回值指向输入字符数组,因此可能有危险(调用者可能希望常量参数保持不变,但如果它的任何部分作为
char*
指针返回,则它是可修改的)

如果未找到匹配字符,函数返回值应为空:

如果未找到所查找的字符,则
strchr
也应返回
NULL
。如果未找到字符时返回非NULL,或者在这种情况下返回s,则调用方(如果他认为行为与strchr相同) 可能会假定结果中的第一个字符实际匹配(没有NULL返回值) 无法判断是否存在匹配)

(我不确定你是否打算这么做。)

下面是执行此操作的函数示例:

我编写并运行了几个关于此函数的测试;我添加了几个非常明显的健全性检查,以避免潜在的崩溃:

const char *mystrchr1(const char *s, int c) {
    if (s == NULL) {
        return NULL;
    }
    if ((c > 255) || (c < 0)) {
        return NULL;
    }
    int s_len;
    int i;
    s_len = strlen(s);
    for (i = 0; i < s_len; i++) {
        if ((char) c == s[i]) {
            return (const char*) &s[i];
        }
    }
    return NULL;
}
const char*mystrchr1(const char*s,int c){
如果(s==NULL){
返回NULL;
}
如果((c>255)|(c<0)){
返回NULL;
}
内苏伦;
int i;
s_len=斯特伦(s);
对于(i=0;i
我认为这实际上是C标准对
strchr()
函数的定义中的一个缺陷。(我很高兴被证明是错误的。)(回复评论,这是否真的是一个缺陷是有争议的;我认为这仍然是一个糟糕的设计。它可以安全地使用,但很容易不安全地使用。)

以下是C标准所说的:

char *strchr(const char *s, int c);
strchr函数定位c (转换为s指向的字符串中的字符 终止空字符被视为字符串的一部分

这意味着该程序:

#include <stdio.h>
#include <string.h>

int main(void) {
    const char *s = "hello";
    char *p = strchr(s, 'l');
    *p = 'L';
    return 0;
}
这意味着,(为了回答您的问题,
strhr()
的C实现必须强制转换其结果,以便将其从
const char*
转换为
char*
,或者执行类似的操作

<>这就是为什么C++在C标准库中的几个变化之一中,用两个重载的同名函数替换< <代码> StRCH(<代码> >:

const char * strchr ( const char * str, int character );
      char * strchr (       char * str, int character );
当然,C不能这样做

一个替代方案是用“函数”>代码> > conchar */COD>替换“<代码> > const char */COD>,另一个则使用<代码> char */COD>并返回 char */COD>。不同于C++,这两个函数必须有不同的名称,也许是代码> Schchr 和<代码> STR。cchr

(历史上,
const
是在定义了
strchr()
之后添加到C中的。这可能是在不破坏现有代码的情况下保留
strchr()
的唯一方法。)

strchr()
不是唯一存在此问题的C标准库函数。受影响函数的列表(我认为此列表是完整的,但我不保证它)是:

(全部在
中声明)和:


(在
中声明)。所有这些函数都使用指向数组初始元素的
const
数据指针,并返回指向该数组元素的非
const
指针。

从非修改函数返回const数据的非const指针实际上是C语言中使用得相当广泛的一种习惯用法。它不一定是它很漂亮,但它已经相当成熟了

<> >这里简单: SrCHR 本身是一个非修改操作。但是我们需要<常数> Strrr < /C>功能,对于常量字符串和非常量字符串,它也将输入的常态传播到输出的稳定性。C语言都不提供C++对这个概念的任何优雅支持,意思是在这两种语言中,您必须编写两个几乎相同的函数,以避免冒const正确性的风险

<>在C++中,你可以通过声明两个函数名为

来使用函数重载
const char *strchr(const char *s, int c);
char *strchr(char *s, int c);
在C中,没有函数重载,因此为了在这种情况下完全强制const正确性,您必须提供两个具有不同名称的函数,例如

const char *strchr_c(const char *s, int c);
char *strchr(char *s, int c);
尽管在某些情况下,这可能是正确的做法,但C标准通常认为(而且是正确的)这太麻烦了,而且涉及面太广
void *bsearch(const void *key, const void *base,
    size_t nmemb, size_t size,
    int (*compar)(const void *, const void *));
const char *strchr(const char *s, int c);
char *strchr(char *s, int c);
const char *strchr_c(const char *s, int c);
char *strchr(char *s, int c);
char *strchr(const char *s, int c);
for (; *s != '\0'; ++s)
  if (*s == c)
    return (char *) s;

return NULL;
for (; *s != '\0' && *s != c; ++s)
  ;

return *s == c ? (char *) s : NULL;