简体   繁体   English

如何在C中使用strlen()找到字符指针的长度?

[英]How can I find the length of a character pointer using strlen() in C?

I am making it clear that my question is exact duplicate of this question. 我明确表示我的问题与这个问题完全相同。

But unfortunately I have one question which any of the answers didn't addressed. 但不幸的是,我有一个问题,任何答案都没有解决。 So the code was:- 所以代码是: -

#include <string.h>

int foo(void) {
  char bar[128];
  char *baz = &bar[0];
  baz[127] = 0;
  return strlen(baz);
}

Question was: What are the possible outputs of this function? 问题是:这个功能的可能输出是什么?

When I run this code, this gives 0 everytime and the correct answers are 0 and 127(I still didn't get why?). 当我运行这段代码时,每次都给出0,正确的答案是0和127(我仍然没有得到原因?)。

My question is how this statement is even valid I mean we are calculating the length of baz which contains a memory address say 0xb96eb740 which is a hex number, so what we are doing is strlen() on this address to find it's length? 我的问题是这个语句是如何有效的我的意思是我们正在计算包​​含内存地址的baz的长度,例如0xb96eb740这是一个十六进制数,所以我们在这个地址上做strlen()来查找它的长度? I mean how can we find length of an address , which is just a number? 我的意思是我们怎样才能找到一个地址的长度,这只是一个数字?

I am really confused and trying to understand it for hours but still not getting it. 真的很困惑,并试图理解它几个小时但仍然没有得到它。

Don't get stuck on the fact that it's being passed an address. 不要因为它被传递一个地址而被困住。 strlen() always takes an address. strlen() 总是占用一个地址。 It's argument is a const char * , the address of a string. 它的参数是一个const char * ,一个字符串的地址。 All of these calls pass the exact same address: 所有这些调用都传递完全相同的地址:

strlen(baz);
strlen(&bar[0]);
strlen(bar);

baz is assigned &bar[0] , so the first and second are equivalent. baz被赋值为&bar[0] ,所以第一个和第二个是等价的。 An array decays to a pointer to its first element ( array == &array[0] ), so the second and third are equivalent. 数组衰减到指向其第一个元素的指针array == &array[0] ),因此第二个和第三个元素是等价的。

I mean how can we find length of an address , which is just a number? 我的意思是我们怎样才能找到一个地址的长度,这只是一个数字?

Let's say that bar == &bar[0] == baz == (char *) 0xb96eb740 as per your example. 假设根据你的例子, bar == &bar[0] == baz == (char *) 0xb96eb740 strlen() will first check if memory location 0xb96eb740 contains \\0 . strlen()将首先检查内存位置0xb96eb740是否包含\\0 If not, it will then check 0xb96eb741. 如果没有,它将检查0xb96eb741。 Then 0xb96eb742. 然后是0xb96eb742。 Then 0xb96eb743. 然后是0xb96eb743。 It will continue checking each location sequentially until it finds \\0 . 它将继续按顺序检查每个位置,直到找到\\0

I know that's true. 我知道那是真的。 But why does strlen(baz) return 0? 但是为什么strlen(baz)返回0?

As the linked Q&A explains, the behavior is indeterminate because the contents of the bar[128] array are uninitialized. 正如链接的问答所解释的那样,行为是不确定的,因为bar[128]数组的内容是未初始化的。 There could be anything in that array. 该阵列中可能有任何内容。 The only cell we know the value of is bar[127] , which is set to \\0 . 我们知道值的唯一单元格是bar[127] ,它被设置为\\0 All the others are uninitialized. 所有其他人都没有初始化。

That means that any one of them, or all of them, or none of them, could contain a \\0 character. 这意味着它们中的任何一个或全部,或者都不包含\\0字符。 It could change from run to run, from call to call even. 它可以从一次运行变为另一次运行,甚至从呼叫到呼叫。 Every time you call foo() you could get a different result. 每次调用foo()都可以得到不同的结果。 That's entirely possible. 这完全有可能。 The result will vary based on what data happens to be on the stack before foo() is called. 结果将根据调用foo()之前堆栈上的数据而变化。

When I run this code, this gives 0 every time and the correct answers are 0 and 127 (I still don't get why?). 当我运行这段代码时,每次都给出0 ,正确的答案是0127 (我仍然不明白为什么?)。

It could return any value between 0 and 127. Due to the indeterminate behavior you mustn't read too much into what the program happens to return when you run it. 它可以在0和127之间的任意值返回由于你一定不要过分解读该程序会发生什么,当你运行它返回不确定的行为。 The output could be different if you run the program again, if you cal a different set of functions before foo() , if you run a different program beforehand, if you change compilers, if you run it a different day of the week, if you use a different operating system, etc., etc., etc. 如果你再次运行程序,如果你在foo()之前调用一组不同的函数,如果你事先运行一个不同的程序,如果你改变编译器,如果你在一周的另一天运行它,如果你运行它,则输出可能会有所不同您使用不同的操作系统等,等等。

My question is how this statement is even valid I mean we are calculating the length of baz which contains a memory address say 0xb96eb740 which is a hex number, so what we are doing is strlen() on this address to find it's length? 我的问题是这个语句是如何有效的我的意思是我们正在计算包​​含内存地址的baz的长度,例如0xb96eb740这是一个十六进制数,所以我们在这个地址上做strlen()来查找它的长度?

The strlen function accepts an address as argument, and its behaviour is to read the character stored at that address. strlen函数接受一个地址作为参数,其行为是读取存储在该地址的字符。 (It does not try to read the characters of the address as you seem to be suggesting). (它不尝试读取地址字符作为你似乎在暗示)。 If that character is not '\\0' then it will read the character at the next address and see if that is '\\0' etc. 如果该字符不是'\\0'那么它将读取下一个地址的字符并查看是否为'\\0'等。

The answer to your question is anything can happen . 你的问题的答案是任何事情都可能发生

The array bar is uninitialized. 阵列bar未初始化。 Only bar[127] is explicitly set to '\\0' . 只有bar[127]显式设置为'\\0' Passing an uninitialized array to strlen() , which you do indirectly by passing baz , which points to bar[0] , has undefined behavior. 将未初始化的数组传递给strlen() ,通过传递指向bar[0] baz间接执行该操作,具有未定义的行为。

In practice, on modern architectures without trap values, function foo() has unspecified behavior and can return any value between 0 and 127 depending on whatever the stack contains when you call it. 实际上,在没有陷阱值的现代体系结构中,函数foo()具有未指定的行为,并且可以返回0127之间的任何值,具体取决于调用时堆栈包含的内容。

In your case it returns 0 because there happens to be a null byte at the beginning of bar , but you cannot rely on that and successive calls to foo() could return different values. 在你的情况下,它返回0因为在bar的开头恰好有一个空字节,但你不能依赖它,并且对foo()连续调用可能返回不同的值。

If you run a program that calls foo() under valgrind or some other memory sanitizing tool, it might complain that strlen() accesses uninitialized memory. 如果你运行一个在valgrind或其他内存清理工具下调用foo()的程序,它可能会抱怨strlen()访问未初始化的内存。

Others have covered that the value is indeterminate , so I go directly to this: 其他人已经说过价值是不确定的 ,所以我直接谈到这个:

I mean how can we find length of an address, which is just a number? 我的意思是我们怎样才能找到一个地址的长度,这只是一个数字?

You don't. 你没有。 The length of a string is calculated by reading the memory sequentially from the address you want to start with and see how far you need to go before you hit the first '\\0' character. 字符串的长度是通过从您想要开始的地址开始按顺序读取内存来计算的,并在您点击第一个'\\0'字符之前查看您需要走多远。 Here is an example of how you can implement a function that returns the length of a string: 下面是一个如何实现返回字符串长度的函数的示例:

int strlen(char * str) {
    int length=0;
    while(str[length] != '\0') 
        length++;
    return length;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM