我试图编写自己的strhr()方法实现。
现在看起来是这样的:
char *mystrchr(const char *s, int c) {
while (*s != (char) c) {
if (!*s++) {
return NULL;
}
}
return (char *)s;
}
最后一行原来是
return s;
但这没用,因为S是康斯特。我发现需要这个演员,但我真的不知道我在那里做什么:(有人能解释一下吗?
最佳答案
我认为这实际上是c标准对strchr()
函数定义的一个缺陷。(我很高兴被证明是错的。)(回复评论,这是否真的是一个缺陷是有争议的;但这仍然是一个糟糕的设计。它可以安全使用,但不安全使用太容易。)
C标准是这样说的:
char *strchr(const char *s, int c);
strhr函数定位c的第一个出现
(转换为字符)由s指向的字符串中。
终止空字符被视为字符串的一部分。
这意味着这个程序:
#include <stdio.h>
#include <string.h>
int main(void) {
const char *s = "hello";
char *p = strchr(s, 'l');
*p = 'L';
return 0;
}
尽管它小心地将指向字符串文本的指针定义为指向
const
char
的指针,但它具有未定义的行为,因为它修改了字符串文本。gcc至少没有对此发出警告,程序会因分段错误而终止。问题是
strchr()
接受一个const char*
参数,这意味着它承诺不会修改s
指向的数据——但它返回一个普通的char*
,这允许调用者修改相同的数据。下面是另一个例子;它没有未定义的行为,但是它悄悄地修改了一个
const
限定对象,而没有任何类型转换(进一步考虑,我相信它有未定义的行为):#include <stdio.h>
#include <string.h>
int main(void) {
const char s[] = "hello";
char *p = strchr(s, 'l');
*p = 'L';
printf("s = \"%s\"\n", s);
return 0;
}
这意味着,我认为(为了回答您的问题),c实现
strchr()
必须转换其结果以将其从const char*
转换为char*
,或者做一些等效的事情。这就是为什么C++在对C标准库进行的少数改动中,用相同名称的两个重载函数替换了cc:
const char * strchr ( const char * str, int character );
char * strchr ( char * str, int character );
当然C不能这么做。
另一种方法是将
strchr()
替换为两个函数,一个使用astrchr
并返回aconst char*
,另一个使用aconst char*
并返回achar*
。与C++不同,这两个函数必须有不同的名称,可能是char*
和strchr
。(历史上,
strcchr
是在定义了const
之后添加到c中的。这可能是在不破坏现有代码的情况下保持strchr()
的唯一方法。strchr()
不是唯一有此问题的c标准库函数。受影响函数的列表(我认为这个列表是完整的,但我不能保证)是:void *memchr(const void *s, int c, size_t n);
char *strchr(const char *s, int c);
char *strpbrk(const char *s1, const char *s2);
char *strrchr(const char *s, int c);
char *strstr(const char *s1, const char *s2);
(均在
strchr()
中声明)和:void *bsearch(const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
(在
<string.h>
中声明)。所有这些函数都接受指向指向数组初始元素的<stdlib.h>
数据的指针,并返回指向该数组元素的非-const
指针。