在C语言中,memcmp、strcmp和strncmp有什么区别?

61

我使用C语言编写了一小段代码来测试C语言中的memcmp()strncmp()strcmp()函数。

以下是我编写的代码:

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

int main() {
        char *word1="apple",*word2="atoms";

        if (strncmp(word1,word2,5)==0)
                printf("strncmp result.\n");
        if (memcmp(word1,word2,5)==0)
                printf("memcmp result.\n");
        if (strcmp(word1,word2)==0)
                printf("strcmp result.\n");
}

有人能解释一下这三个函数的区别吗?我对它们很困惑。

我的主要问题是,我有一个文件,我对其进行了分词处理,但问题在于,当我在文件中分词单词“atoms”时,我必须停止分词过程。

我首先尝试使用strcmp(),但不幸的是,当它到达文件中放置单词“atoms”的位置时,它没有停止,而是继续执行,但当我使用memcmp()strncmp()时,它停止了,我很高兴。

但后来我想,如果有这样一种情况,即有一个字符串,其中前5个字母是a、t、o、m、s,后面跟着其他字母,该怎么办呢?

不幸的是,我的想法是正确的,因为我使用上述代码通过将word1初始化为“atomsaaaaa”,word2初始化为“atoms”,并在if语句中使用memcmp()strncmp()进行测试时返回了0。另一方面,strcmp()却没有。看来我必须使用strcmp()


2
夸赞你包含了源代码。如果你展示一下你得到的结果和期望的结果,那么你的问题会更加清晰明了。 - Pascal Cuoq
举个例子,如果我将word1初始化为“atomr”,将word2初始化为“atoms”,当我运行可执行文件时包含memcmp()的if语句从未为真。 - und3rd06012
@PascalCuoq。好的,我找到了问题的答案。 - und3rd06012
@el10780:不,我指的是手册页面。例如,像这样 - http://www.kernel.org/doc/man-pages/online/pages/man3/memcmp.3.html。 - user405725
是的,我看过这些页面,但我有点困惑。也许是因为我累了吧。现在已经凌晨3点了。在搜索这个问题之前,我不会轻易发问,会先在这里和互联网上查找相关信息。 - und3rd06012
2
值得注意的是,由于通常会针对单个加载和存储使用支持的最大类型进行优化,因此memcmp可能会更快。因此,它实际上一次比较多个字符,而不是一个字符,可能是8个字符的比较,至少可能是4个字符的比较。 - 2013Asker
6个回答

133

简而言之:

  • strcmp 用于比较以 null 结尾的 C 字符串
  • strncmp 用于比较最多 N 个以 null 结尾的 C 字符串
  • memcmp 用于比较 N 个二进制字节缓冲区

因此,如果您有这些字符串:

const char s1[] = "atoms\0\0\0\0";  // extra null bytes at end
const char s2[] = "atoms\0abc";     // embedded null byte
const char s3[] = "atomsaaa";

那么这些结果是成立的:

strcmp(s1, s2) == 0      // strcmp stops at null terminator
strcmp(s1, s3) != 0      // Strings are different
strncmp(s1, s3, 5) == 0  // First 5 characters of strings are the same
memcmp(s1, s3, 5) == 0   // First 5 bytes are the same
strncmp(s1, s2, 8) == 0  // Strings are the same up through the null terminator
memcmp(s1, s2, 8) != 0   // First 8 bytes are different

1
谢谢Adam。你的回答很清楚地解释了这三个函数的使用。 - und3rd06012
1
意味着memcmp与strcmp类似,但是等于0的字节不被视为比较终止符。因此,strcmp基本上使用以空字符终止的字符串的属性。 - Sarwan
非常好的答案。我刚刚花了几个小时试图弄清楚为什么比较两个24字节(未以null结尾)的字符串返回0的概率约为50%,而其余时间则返回一些随机值。 memcmp 绝对是我应该使用的函数。 - mreff555

10

memcmp 函数用于比较一定数量的字节。 而 strcmp 等函数用于比较字符串

您在示例中有些取巧,因为您知道两个字符串都是5个字符长(加上空字符结尾)。但是,如果您不知道字符串的长度,这种情况往往会发生怎么办?好吧,您可以使用 strcmp,因为它知道如何处理字符串memcmp 不知道。

memcmp 的功能主要是比较字节序列。如果您知道每个字符串的长度,那么确实可以使用 memcmp 来比较它们,但这种情况有多少呢?很少。通常需要字符串比较函数,因为...它们知道什么是字符串以及如何进行比较。

至于您遇到的其他问题,从您的问题和代码中无法清楚地了解。但可以肯定的是,strcmp 在字符串比较方面比 memcmp 更具备普遍适用性。


让我换一种方式问。如果我使用memcmp,并将word1初始化为“atomr”,将word2初始化为“atoms”,它会返回0吗? - und3rd06012
@el10780:这取决于您传递给它的长度。如果您要求memcmp比较4个或更少的字节,则它将返回0(相等);如果您要求它比较5个或更多的字节,则它将返回非0(不相等)。 - Adam Rosenfield
请原谅我的无知,我无法理解“atoms”和“atomr”的字节序列之间的区别。它们的大小是相同的,对吗?但是,“atomr”的字节序列是97、116、111、109、114,“atoms”的字节序列是97、116、111、109、115。因此,如果对所有五个字符进行memcmp检查,它将不会返回0。无论如何,感谢您的快速回复和帮助。 - und3rd06012

3

总结一下:

  • strncmp()和strcmp()将0字节视为字符串的结尾,并且不会比较它之后的内容

  • 对于memcmp()来说,0字节没有特殊含义


2

strcmp():

  • 该函数用于比较存储在两个变量中的两个字符串,比较它们需要一些时间。因此,它会减慢进程速度。

strncmp():

  • 这个函数与前一个函数非常相似,但是它仅比较前n个字符。这也会减慢进程速度。

memcmp():

  • 这个函数是用于使用内存比较两个变量。它不是逐个比较它们,而是每次比较四个字符。如果您的程序对速度非常关注,我建议使用memcmp()。

9
-1 是因为这是不正确的,并且基于速度和实现的许多无根据的假设,例如 strcmp 和 strncmp 的速度,以及 memcmp 一次读取多少个字。完全没有正确回答问题。 - Wiz
5
与 Wiz 的观点相反,Arvid 是唯一一个解释了 memcmp 相对于 strncmp 具有巨大速度优势的人。他只是没有提到对齐优化。在大多数编译器中,memcmp 确实是比较单词而不是字符。 因此,它可能会超出字符串范围,导致 valgrind 警告。 您不需要解释缓冲区与字符串之间的区别。 - rurban
试图争论这种差异是荒谬的。现代libc中memcmp和strcmp之间唯一的区别是strcmp必须检查是否需要停止,这比仅比较字节需要更多时间。我个人进行了基准测试,并且只测量了memcmp和strcmp之间速度约为10%的差异。 - Gabriel Ravier
@GabrielRavier 如果你需要进行大量比较,且已经知道字符串的大小,那么如果你问我,10%的差异并不是那么微小。 - Tachi
1
@Tachi,问题在于帖子的表述非常草率,并且给出了关于最佳方法使用的非常错误的指示。您的建议是有效的,但答案暗示memcmpstrncmp具有某种巨大的速度优势,而10%并不算什么。 - Gabriel Ravier

1

strncmp和memcmp基本相同,除了前者要考虑到以NULL结尾的字符串。


1

对于strcmp,您只想比较您知道将是字符串的内容,但有时这并不总是正确的,例如读取二进制文件中的行,因此您需要使用memcmp来比较包含NUL字符但匹配的某些输入行,您可能希望继续检查更多长度的输入。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接