如果 c == '\0',函数 Strrchr 如何找到最后一个 c?
How does the function Strrchr finds the last c if c == '\0'?
例如 char *p
指向 "there is so [=11=]ma[=11=]ny [=11=] \0 in t[=11=]his stri[=11=]ng ![=11=][=11=][=11=][=11=]"
中的第一个字符,
Strrchr()
如何找到最后一次出现的空字符?
出现以下问题:
=>停止循环需要什么条件!
=>我认为在所有情况下它都会尝试访问下一个内存区域以检查其条件?在某些时候绕过字符串边界,UB!所以安全吗!
如有错误欢迎指正!
在您提供的情况下,您永远无法知道找到的空字符是否是最后一个字符,因为您无法保证字符串的结尾。因为它是一个 c 字符串,所以可以保证字符串以 '\0' 结尾,但如果您决定超越它,您将无法知道您正在访问的内存是否是您的。从数组中访问内存具有未定义的行为,因为您可以只访问内存中属于您的下一个对象,或者您可以触摸未分配的内存,但它的块仍然属于您的进程,或者您可以尝试触摸一个根本不属于您的细分市场。只有第三个会导致 SIGSEGV。您可以看到 问题来检查分段错误而不会使您的程序崩溃,但是您的字符串可能在您以这种方式捕获它之前就已经结束了。
字符串有一个结束字符是有原因的。如果您坚持在字符串的多个位置使用 \0,您可以用另一个字符终止,但请注意,所有库函数仍会将第一个 \0 视为字符串的结尾。
在字符串中使用多个 \0 被认为是一种不好的做法,也是一件非常糟糕的事情,所以如果可以的话,请避免使用它。
很简单,如评论中所述。
first [=16=]
是 C 字符串中的最后一个也是唯一一个。
所以如果你写
char *str = "there is so [=10=]ma[=10=]ny [=10=] \0 in t[=10=]his stri[=10=]ng ![=10=][=10=][=10=][=10=]";
char *p = strrchr(str, 's');
printf("%s\n", p);
它将打印
so
因为strchr
会在“so”中找到's',也就是你给它的字符串中的最后一个's'。并且(回答你的具体问题)如果你写
p = strrchr(str, '[=12=]');
printf("%d %s\n", (int)(p - str), p+1);
它将打印
12 ma
证明 strchr
找到了 第一个 [=16=]
.
很明显,str
是一个长字符串,其中嵌入了一些 [=16=]
。但是,在 C 语言中, 没有 这样的东西作为“其中嵌入了 [=16=]
的字符串”。根据定义,C 字符串不可能包含嵌入的 [=16=]
。根据定义,第一个 [=16=]
结束字符串。
还有一点。您曾提到,如果您要“访问下一个内存区域”,您将“在某个时候绕过字符串边界,UB!”你是对的。在我的回答中,当我说
p = strrchr(str, '[=12=]');
printf("%d %s\n", (int)(p - str), p+1);
这里,p
指向 strrchr
认为是字符串的结尾,所以当我计算 p+1
并尝试使用 %s
打印它时,如果我们不知道更好,看起来我确实误入了未定义的行为。在这种情况下,当然是安全的,因为我们确切地知道第一个 [=16=]
之外的内容。但是如果我写
char *str2 = "hello";
p = strrchr(str2, '[=15=]');
printf("%s\n", p+1); /* WRONG */
那我肯定过关了
“一个字符串”、“一个字符数组”和“一个 char* 指针”是有区别的。
- C 字符串是由空字符终止的字符数。
- 字符数组是定义的字符数。
- char* 指针在技术上是指向单个字符的指针,但通常用于标记 C 风格字符串中的一个点。
你说你有一个指向字符(char*p
)的指针并且*p
的值是't'
,但是你认为*p是一个C的第一个字符样式字符串
"there is so [=13=]ma[=13=]ny [=13=] \0 in t[=13=]his stri[=13=]ng ![=13=][=13=][=13=][=13=]"
.
正如其他人所说,因为你说这是一个 C 风格的字符串并且你不知道它的长度那么 p
之后的第一个 null 将标记字符串的结尾。
如果这是一个字符数组 char str[40]
那么您可以通过从数组末尾向开头循环来找到最后一个 null for (i=39; i>=0; i--)
但是您不知道长度,因此不行。
希望对您有所帮助,如果我误入了 C++,请原谅,我使用 C 已有 25 年了:)
例如 char *p
指向 "there is so [=11=]ma[=11=]ny [=11=] \0 in t[=11=]his stri[=11=]ng ![=11=][=11=][=11=][=11=]"
中的第一个字符,
Strrchr()
如何找到最后一次出现的空字符?
出现以下问题:
=>停止循环需要什么条件!
=>我认为在所有情况下它都会尝试访问下一个内存区域以检查其条件?在某些时候绕过字符串边界,UB!所以安全吗!
如有错误欢迎指正!
在您提供的情况下,您永远无法知道找到的空字符是否是最后一个字符,因为您无法保证字符串的结尾。因为它是一个 c 字符串,所以可以保证字符串以 '\0' 结尾,但如果您决定超越它,您将无法知道您正在访问的内存是否是您的。从数组中访问内存具有未定义的行为,因为您可以只访问内存中属于您的下一个对象,或者您可以触摸未分配的内存,但它的块仍然属于您的进程,或者您可以尝试触摸一个根本不属于您的细分市场。只有第三个会导致 SIGSEGV。您可以看到
字符串有一个结束字符是有原因的。如果您坚持在字符串的多个位置使用 \0,您可以用另一个字符终止,但请注意,所有库函数仍会将第一个 \0 视为字符串的结尾。
在字符串中使用多个 \0 被认为是一种不好的做法,也是一件非常糟糕的事情,所以如果可以的话,请避免使用它。
很简单,如评论中所述。
first [=16=]
是 C 字符串中的最后一个也是唯一一个。
所以如果你写
char *str = "there is so [=10=]ma[=10=]ny [=10=] \0 in t[=10=]his stri[=10=]ng ![=10=][=10=][=10=][=10=]";
char *p = strrchr(str, 's');
printf("%s\n", p);
它将打印
so
因为strchr
会在“so”中找到's',也就是你给它的字符串中的最后一个's'。并且(回答你的具体问题)如果你写
p = strrchr(str, '[=12=]');
printf("%d %s\n", (int)(p - str), p+1);
它将打印
12 ma
证明 strchr
找到了 第一个 [=16=]
.
很明显,str
是一个长字符串,其中嵌入了一些 [=16=]
。但是,在 C 语言中, 没有 这样的东西作为“其中嵌入了 [=16=]
的字符串”。根据定义,C 字符串不可能包含嵌入的 [=16=]
。根据定义,第一个 [=16=]
结束字符串。
还有一点。您曾提到,如果您要“访问下一个内存区域”,您将“在某个时候绕过字符串边界,UB!”你是对的。在我的回答中,当我说
p = strrchr(str, '[=12=]');
printf("%d %s\n", (int)(p - str), p+1);
这里,p
指向 strrchr
认为是字符串的结尾,所以当我计算 p+1
并尝试使用 %s
打印它时,如果我们不知道更好,看起来我确实误入了未定义的行为。在这种情况下,当然是安全的,因为我们确切地知道第一个 [=16=]
之外的内容。但是如果我写
char *str2 = "hello";
p = strrchr(str2, '[=15=]');
printf("%s\n", p+1); /* WRONG */
那我肯定过关了
“一个字符串”、“一个字符数组”和“一个 char* 指针”是有区别的。
- C 字符串是由空字符终止的字符数。
- 字符数组是定义的字符数。
- char* 指针在技术上是指向单个字符的指针,但通常用于标记 C 风格字符串中的一个点。
你说你有一个指向字符(char*p
)的指针并且*p
的值是't'
,但是你认为*p是一个C的第一个字符样式字符串
"there is so [=13=]ma[=13=]ny [=13=] \0 in t[=13=]his stri[=13=]ng ![=13=][=13=][=13=][=13=]"
.
正如其他人所说,因为你说这是一个 C 风格的字符串并且你不知道它的长度那么 p
之后的第一个 null 将标记字符串的结尾。
如果这是一个字符数组 char str[40]
那么您可以通过从数组末尾向开头循环来找到最后一个 null for (i=39; i>=0; i--)
但是您不知道长度,因此不行。
希望对您有所帮助,如果我误入了 C++,请原谅,我使用 C 已有 25 年了:)