如何和strchr执行工作 [英] How does strchr implementation work

查看:116
本文介绍了如何和strchr执行工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试着写我自己的实施和strchr()方法。

现在看起来是这样的:

 的char * mystrchr(为const char * S,诠释三){
    而(* S!=(char)的C){
        如果(!* S ++){
            返回NULL;
        }
    }
    回报(字符*)S;
}

最后一行原本是

 返回小号;

但这并没有工作,因为s是常数。我发现,需要有这个转换(字符*),但我真的不知道我在做什么有:(有人能解释一下吗?


解决方案

我认为这实际上是在和strchr()函数的C标准的定义的一个漏洞。 (我很乐意被证明是错误的。)(回复的意见,这是值得商榷的是否真的是一个缺陷。恕我直言,它仍然是设计不良它的可以的安全使用,但它太容易不安全使用)。

下面是C标准说的话:

 的char *和strchr(为const char * S,INT C);


  

和strchr 功能定位中第一次出现的 C
  通过的取值(转换为字符)字符串中指出。该
  终止空字符被认为是字符串的一部分。


这意味着,此程序:

 的#include<&stdio.h中GT;
#包括LT&;&string.h中GT;诠释主要(无效){
    为const char * s =你好;
    的char * p =和strchr(S,'L');
    * p值=L;
    返回0;
}

即使仔细定义指向字符串为常量,是未定义的行为,因为它修改字符串。 GCC,至少,没有警告这一点,并且程序段故障死亡。

问题是,和strchr()需要为const char * 的说法,这意味着它承诺不修改该数据取值点 - 但它返回一个纯的char * ,允许调用者修改同一数据。

下面是另一个例子; <击>它不具有不确定的行为,但它悄悄地修改了常量限定的对象没有任何强制类型转换(其中,在进一步的思考,我相信是未定义行为):

 的#include&LT;&stdio.h中GT;
#包括LT&;&string.h中GT;诠释主要(无效){
    为const char S [] =你好;
    的char * p =和strchr(S,'L');
    * p值=L;
    的printf(S = \\%s \\的\\ N,S);
    返回0;
}

这意味着,我认为,(回答你的问题)的和strchr的C实现()有投它的结果将其从为const char * 到的char * ,或做一些相当于

这也是为什么C ++,在它对C标准库中的一些变化之一,替换和strchr()通过两个同名的重载函数:

 为const char *和strchr(为const char * str中,诠释人物);
      字符*和strchr(的char * str中,诠释人物);

当然的C无法做到这一点。

另一种做法是由两个功能,一是采取了为const char * 键,返回到替换和strchr 返回的char * ,另外服用的char * 和C $ C>。不像在C ++中,这两个函数就必须有不同的名称,也许和strchr strcchr

(从历史上看,常量已在和strchr()已经定义添加到C,这是可能的只有这样,才能保持和strchr()不打破现有code)

和strchr()是不是有这个问题的唯一C标准库函数。受影响的功能(我的认为的这份名单是完整的,但我不保证它)的列表是:

  void *的了memchr(常量无效* S,INT C,为size_t n)的;
字符*和strchr(为const char * S,INT C);
的char * strpbrk(为const char * S1,为const char * S2);
的char * strrchr(为const char * S,INT C);
字符*的strstr(为const char * S1,为const char * S2);

(全部在声明&LT;&string.h中GT; )和

 的void * bsearch(常量无效*键,常量无效*基地​​,
    为size_t nmemb个,为size_t大小,
    INT(* COMPAR)(常量无效*,常量无效*));

(在&LT宣布;文件stdlib.h&GT; )。所有这些功能需要一个指向常量指向数组的初始元素的数据,并返回一个非 - 常量指针指向数组的元素

I tried to write my own implementation of the strchr() method.

It now looks like this:

char *mystrchr(const char *s, int c) {
    while (*s != (char) c) {
        if (!*s++) {
            return NULL;
        }
    }
    return (char *)s;
}

The last line originally was

return s;

But this didn't work because s is const. I found out that there needs to be this cast (char *), but I honestly don't know what I am doing there :( Can someone explain?

解决方案

I believe this is actually a flaw in the C Standard's definition of the strchr() function. (I'll be happy to be proven wrong.) (Replying to the comments, it's arguable whether it's really a flaw; IMHO it's still poor design. It can be used safely, but it's too easy to use it unsafely.)

Here's what the C standard says:

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

The strchr function locates the first occurrence of c (converted to a char) in the string pointed to by s. The terminating null character is considered to be part of the string.

Which means that this program:

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

int main(void) {
    const char *s = "hello";
    char *p = strchr(s, 'l');
    *p = 'L';
    return 0;
}

even though it carefully defines the pointer to the string literal as const, has undefined behavior, since it modifies the string literal. gcc, at least, doesn't warn about this, and the program dies with a segmentation fault.

The problem is that strchr() takes a const char* argument, which means it promises not to modify the data that s points to -- but it returns a plain char*, which permits the caller to modify the same data.

Here's another example; it doesn't have undefined behavior, but it quietly modifies a const qualified object without any casts (which, on further thought, I believe has undefined behavior):

#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;
}

Which means, I think, (to answer your question) that a C implementation of strchr() has to cast its result to convert it from const char* to char*, or do something equivalent.

This is why C++, in one of the few changes it makes to the C standard library, replaces strchr() with two overloaded functions of the same name:

const char * strchr ( const char * str, int character );
      char * strchr (       char * str, int character );

Of course C can't do this.

An alternative would have been to replace strchr by two functions, one taking a const char* and returning a const char*, and another taking a char* and returning a char*. Unlike in C++, the two functions would have to have different names, perhaps strchr and strcchr.

(Historically, const was added to C after strchr() had already been defined. This was probably the only way to keep strchr() without breaking existing code.)

strchr() is not the only C standard library function that has this problem. The list of affected function (I think this list is complete but I don't guarantee it) is:

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);

(all declared in <string.h>) and:

void *bsearch(const void *key, const void *base,
    size_t nmemb, size_t size,
    int (*compar)(const void *, const void *));

(declared in <stdlib.h>). All these functions take a pointer to const data that points to the initial element of an array, and return a non-const pointer to an element of that array.

这篇关于如何和strchr执行工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆