通常建议使用strncmp
而不是strcmp
,有什么好处?我认为这可能与安全有关。如果是这种情况,如果已知其中一个输入字符串是文字常量,如"LiteralString"
?
更新
我的意思是在需要比较整个字符串的相同用户场景下,strncmp
可以如下使用。我想知道它是否有意义。
strncmp(inputString, "LiternalString", strlen("LiternalString"));
答案 0 :(得分:19)
strcmp
的问题在于,有时,如果错误,传递的参数不是有效的C字符串(意味着p1或p2不以空字符终止,即不NULL-terminated String)然后,strcmp继续比较,直到它到达不可访问的内存并崩溃或有时导致意外行为。
使用strncmp
,您可以限制搜索,以便它无法访问不可访问的内存。
但是,从那以后,不应该说strcmp
是不安全的。这两种功能都非常适合它们的工作方式。程序员在使用之前应该阅读该函数的man
页面,并且在将参数传递给这些库函数时必须足够诚恳。
您还可以阅读包含几乎相似问题的THIS。
答案 1 :(得分:11)
strncmp
没有“超过strcmp
的优势”;而是他们解决不同的问题。 strcmp
用于确定两个字符串是否相等(如果不相等,可能如何相对于彼此对它们进行排序/排序)。 strncmp
(主要)用于确定字符串是否以特定前缀开头。例如:
if (strncmp(str, "--option=", 9)==0)
将确定str
是否以"--option="
开头。 strcmp
无法修改要检查的字符串(可能不是有效操作)或制作无用的副本,这是无法实现的。使用memcmp
也无法实现,除非您已经知道str
指向一个长度至少为9个字节的对象;否则对memcmp
的调用将具有未定义的行为。
strncmp
还有其他用例,例如使用非C字符串数据。
答案 2 :(得分:8)
答案 3 :(得分:0)
在这里发布一个反strncmp用例。 想想以下代码。
#include <stdio.h>
#include <dirent.h>
int main()
{
//I want to list all files under current folder, include hidden files.
DIR *dir;
struct dirent *dp;
char * file_name;
dir = opendir(".");
while ((dp=readdir(dir)) != NULL) {
printf("debug: %s\n", dp->d_name);
if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..") )
//It doesn't work if you replace strcmp with strncmp here.
//if ( !strncmp(dp->d_name, ".", 1) || !strncmp(dp->d_name, "..", 2) )
{
} else {
file_name = dp->d_name;
printf("file_name: \"%s\"\n",file_name);
}
}
closedir(dir);
return 0;
}
答案 4 :(得分:0)
int ret1, ret2;
char dev1[] = { "ABC" };
char dev2[4] = { "ABC" };
dev2[3] = 'D';
ret1 = strncmp(dev1,dev2,strlen(dev1)); // # of characters
ret2 = strncmp(dev1,dev2,sizeof(dev1)); // # of characters plus '\0'
假设:dev1为空终止,dev2可能不是。 ret1 = 0(假阳性结果),而不是ret2 = -1(有效结果)
fazit:strncmp不仅仅是strcmp更安全的方式。取决于你如何使用它。
我会在字符串上使用strcmp,在子字符串搜索上使用strncmp。
答案 5 :(得分:0)
...在需要比较整个字符串的相同用户方案下,...
strncmp(inputString, "LiternalString", strlen("LiternalString"));
考虑字符串inputString
长于 string文字的情况。
const char *inputString = "LiternalString_XYZ";
int cmp = strncmp(inputString, "LiternalString", strlen("LiternalString"));
printf("%d\n", cmp); // prints 0.
但是OP希望整个字符串进行比较。
const char *inputString = "LiternalString_XYZ";
int cmp = strcmp(inputString, "LiternalString");
printf("%d\n", cmp); // prints non-zero.
对OP直接问题的结论
我想知道这是否有意义
不。要比较整个字符串,strncmp()
无法始终如一地提供正确的结果。使用strcmp()
。
进一步
strncmp(s1,s2,n)
可以限制搜索,从而不会到达不可访问的内存如果 n
得到了正确的计算-这在OP的代码中没有完成并且存在问题当n
和s1
的最佳s2
不同时正确地做。
大小限制n
既适用于s1
,也适用于s2
,因此,此功能可用于比较前缀,而不是“更安全”。
在OP的情况下,由于 string文字作为 string文字 ,由于“安全性”,没有理由限制搜索总是包含一个终止的空字符。
如果有的话,n
应该基于inputString
的某些属性。
类似strncmp(s1, string_literal, strlen(s1))
的代码在功能上不正确,因为比较未输入空字符。 strncmp(s1, string_literal, strlen(s1)+1)
稍好一点,但是在功能上与简单的strcmp(s1, string_literal)
相同,但没有降低“安全性”。
如果foo()
不能正确形成 strings ,下面提供一些改进的“安全性”,但是如果N != M
如上所述,可能会提供错误的答案。
char s1[N];
foo(s1); // populate s1 somehow
int cmp = strncmp(s1, string_literal, sizeof s1);
char s1[N];
char s2[M];
foo(s1); // populate s1 somehow
foo(s2); // populate s2 somehow
int cmp = strncmp(s1, s2, min(sizeof s1, sizeof s2));
但是在这些情况下,问题出在foo()
上,而不是这里。
对我来说,如果foo()
如此令人怀疑,我会使用以下
s1[sizeof s1 - 1] = '\0';
s2[sizeof s2 - 1] = '\0';
int cmp = strcmp(s1, s2);
或检测到foo()
没有形成 string 。
char s1[N];
foo(s1);
if (memchr(s1, '\0', sizeof s1) == NULL) Oops();
故事的寓意:strncmp()
不是strcmp()
的“更安全”版本。它是另一项工作的工具:比较字符串前缀。
答案 6 :(得分:-1)
使用strn的缺点是在计数器上进行额外的比较和减少操作。
简而言之:strncmp比strcmp更安全,但它也更慢。
答案 7 :(得分:-2)
我只能看到一个优点,即strncmp执行的时间比strcmp少一些,因为我们总是将字符串的前缀与comapre比较,而不是整个字符串。
我认为strcmp和strncmp算法不涉及任何安全方面。它们是相同的,除了在strncmp中只比较第一个'n'字符。
答案 8 :(得分:-4)
strncmp比strcmp
更安全与strncpy和strcpy或strlen和strnlen相同,因为strcmp会比较,直到找到第一个zeroterminator。 strncmp比较直到第一个zeroterminator但最多n个字符。因此,如果您的字符串具有定义的长度,则最好使用strn * -functions。
另见
http://www.cplusplus.com/reference/cstring/strncmp/?kw=strncmp