【问题标题】:C Programming - Functionality of strlenC 编程 - strlen 的功能
【发布时间】:2014-02-28 02:13:31
【问题描述】:

我正在努力尝试理解一些字符串函数,以便在以后的编码项目中更有效地使用它们,所以我设置了下面的简单程序:

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

int main (void)
{
// Declare variables:
char test_string[5];
char test_string2[] = { 'G', 'O', '_', 'T', 'E', 'S', 'T'};
int init; 
int length = 0;
int match;

// Initialize array:
for (init = 0; init < strlen(test_string); init++)
{    test_string[init] = '\0';
}

// Fill array:
test_string[0] = 'T';
test_string[1] = 'E';
test_string[2] = 'S';
test_string[3] = 'T';

// Get Length:
length = strlen(test_string);

// Get number of characters from string 1 in string 2:
match = strspn(test_string, test_string2);

printf("\nstrlen return = %d", length);
printf("\nstrspn return = %d\n\n", match);

return 0;
}

我希望看到:

strlen 返回 = 4 strspn 返回 = 4

但是,我看到 strlen return = 6 和 strspn return = 4。据我了解,char test_string[5] 应该分配 5 个字节的内存并将十六进制 00 放入第五个字节。然后 for 循环(甚至不应该是必要的)应将 test_string 的所有内存字节设置为十六进制 00。然后,立即进行的行应填充 test_string 字节 1 到 4(或 test_string[0] 到 test_string[3])用我指定的。此时调用 strlen 应该返回一个 4,因为它应该从字符串 0 的地址开始并计数一个增量,直到它遇到第一个空字符,它位于字符串 [4] 处。然而 strlen 返回 6。任何人都可以解释一下吗?谢谢!

【问题讨论】:

  • 欢迎来到 Stack Overflow。请阅读About 页面。请注意,您问题中的说法是不可信的; strlen() 既简单又经过广泛测试。如果它是错误的,那将是一个众所周知的问题(很快就会得到解决)。因此,您的问题是 strlen() 没有给您预期的结果,但您的预期错误的可能性比 strlen() 错误的可能性更大。
  • 嗨乔纳森,我想这个问题的标题不好。我绝对知道 strlen 写得正确,没有任何问题,而且我的问题是由于我正在做的事情,我只是无法弄清楚它对我的生活有什么影响。在加入之前,我快速浏览了 about 页面,但我会在一分钟内为您完整阅读。谢谢!
  • 看看你的 init 循环的上限。我在这里根本看不到任何可以将 NULL 字节放入您的字符串的代码。 (提示:分配没有初始化器的变量并不能保证那里的内存内容。)
  • BRPocock,谢谢。我意识到你的暗示与其他给出答案的人交谈,并发现问题确实在我的初始化循环中。正如许多人指出的那样,最好的主意是: char test_string[] = "TEST";和 char test_string2[] = "GO_TEST"; - 我不知道为什么我没想过要使用这些,因为那个技巧是我过去拉过很多很多次的。显然,在我大约 1.5 年的编码中,我仍然没有了解到编译器不是我的朋友哈哈。 C 是一种非常高效的语言,我只需要在做出假设之前确保我知道它是如何运行的。

标签: c string strlen


【解决方案1】:
char test_string[5];

test_string 是一个由 5 个未初始化 char 对象组成的数组。

for (init = 0; init < strlen(test_string); init++)

卡布姆。 strlen 扫描第一个 '\0' 空字符。由于test_string 的内容是垃圾,因此行为未定义。如果碰巧有一个空字符,它可能会返回一个小值,或者如果test_string 中没有任何零字节,它可能会返回一个大值或程序崩溃。

即使不是这样,在for 循环的标头中评估strlen() 也是低效的。每个strlen() 调用都必须重新扫描整个字符串(假设你给了它一个有效的字符串),所以如果你的循环有效,它将是 O(N2)。

如果您希望 test_string 只包含零字节,您可以这样初始化它:

char test_string[5] = "";

或者,因为您稍后初始化前 4 个字节:

char test_string[5] = "TEST";

或者只是:

char test_string[] = "TEST";

(后者让编译器确定它需要 5 个字节。)

回到你的声明:

char test_string2[] = { 'G', 'O', '_', 'T', 'E', 'S', 'T'};

这会导致test_string2 的长度为 7 个字节,没有结尾的 '\0' 字符。这意味着将test_string2 传递给任何需要指向字符串的指针的函数都会导致未定义的行为。你可能想要这样的东西:

char test_string2[] = "GO_TEST";

【讨论】:

  • 感谢您的回复!正如我对其他两个答案所说的那样,我没有意识到a)只有名称和大小的声明不会将空字符放入字符串中,b)我在没有首先初始化所有的情况下为循环调用 strlen test_string 中的数据(我的意思是看代码,我可以告诉你,我写的时候完全没有考虑过)。另外,感谢您指出 test_string2 init 语句的问题。我原以为放置 [] 会告诉编译器将空字符放在末尾,但似乎情况并非如此
  • @RyanBarker:C 中的“字符串”是数据布局,而不是数据类型;它被定义为“由第一个空字符终止并包括第一个空字符的连续字符序列”。 char 的数组可能包含也可能不包含字符串,编译器不会假定它会包含字符串。字符串文字(几乎总是)以空值结尾;字符数组不是。
  • 这就是我在阅读您的回答后的想法,但非常感谢您确认。非常感谢您的帮助!
【解决方案2】:

strlen 搜索 '\0' 字符来计算它们,在您的 test_string 中,没有,所以它会继续,直到找到一个恰好距离数组开头 6 个字节的字符,因为它未初始化。

编译器不会生成代码来初始化数组,因此如果您稍后填充它,您无需支付运行该代码的费用。

要将其初始化为0并跳过循环,您可以使用

char test_string[5] = {0};

这样,所有字符都将被初始化为 0,并且你的 strlen 将在你用“TEST”填充数组后工作。

【讨论】:

  • 但是在 test_string 中有一个空值,特别是在 test_string[4]。我设置的 for 循环甚至可以作为双重检查,除非我只是遗漏了一些东西。
  • 不一定,我敢打赌循环不会像你想象的那样迭代,因为运行时 test_string 中可能有任何东西。
  • @RyanBarker 您的 init 循环本身使用 strlen,除非您有一个空终止符,否则无法使用它。
  • 谢谢!我没想到。将 for 循环中的条件更改为 init
【解决方案3】:

这里有一些问题。首先,char test_string[5]; 只是为该字符串留出 5 个字节,但没有将字节设置为任何内容。特别是,当你说“char test_string[5] 应该分配 5 个字节的内存并将十六进制 00 放入第五个字节”时,第二部分是错误的。

其次,您的数组初始化循环使用strlen(test_string),但由于 test_string 的字节未初始化,因此无法知道其中的内容,因此 strlen(test_string) 返回一些未定义的结果。清除数组的更好方法是memset( test_string, 0, sizeof(test_string) );

您用“TEST”填充数组,但没有在末尾设置 NULL 字节,因此最后一个字节仍未初始化。如果你做上面的 memset 这将被修复,或者你可以手动做test_string[4] = '\0'

【讨论】:

  • 对不起,我没有早点回复这个……其他答案发生得太快了,我还在回复第一个。无论如何,谢谢你。我没有考虑到内存中很可能有一个 null 的事实,所以我不能使用 strlen 直到我确保字符串中的第一个 null 位于它的末尾。此外,感谢您让我知道初始化语句不会将我的 null 设置为更多 - 这对将来非常有用。
猜你喜欢
  • 2016-01-24
  • 2014-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
  • 2023-03-17
相关资源
最近更新 更多