这最初发布在 Code Review 上,建议Stack Overflow更合适......
在寻找一种搜索和捕获子字符串的方法时,我对此进行了编码:
char string[] = {"this is the source string to search"};
char substring[] = {"string to"};
char *target;
char buf[80];
int main(void)
{
target = strstr(string, substring);
int len = strlen(target);
strncpy(buf, target, len);
buf[len]=0;
return 0;
}
我的问题: 可以使用指针char * target这里使用的方式可能会调用未定义的行为。如果是,怎么样?
答案 0 :(得分:2)
此特定代码(使用您正在使用的特定数据)不会调用未定义的行为。但是,对数据的一些轻微更改将调用未定义的行为,因此您的代码非常非常危险。
如果“substring”不是“string”的子字符串,或者它是一个子字符串,并且它的第一次出现在“string”结尾之前是80字节或更多,则会发生未定义的行为。
顺便说一句。 strncpy(buf,target,len); buf [len] = 0;将与strcpy(buf,target)完全相同,因为len == strlen(target)。一般来说,使用strncpy是一个等待发生的事故。
答案 1 :(得分:2)
问题中显示的代码是'OK'(带有轻微咬紧的牙齿),如果要写的是从第一次出现子字符串开始到通用'副本的大纲'有多个问题字符串的结尾是另一个字符串'function。
更详细:
strncpy()
测量子字符串的长度,假设有一个,然后故意无法将空终止符复制到buf
,并故意忽略buf
的大小,尽管它确实在strncpy()
之后显式空终止复制的数据。根据显示的代码,这无关紧要;字符串足够短并且buf
足够大(并且buf
是零初始化的全局变量 - 尽管问及为什么target
和buf
不是本地变量是有效的变量)。memcpy()
的评论是有效的。您也可以使用len + 1
复制空字节,保存显式赋值,但您仍应限制自己复制的数据不能超过buf
中的数据。buf
,或者您是否应该完全拒绝该操作,还应考虑截断是否合适。memmove()
而不是memcpy()
,因为无论源和目标区域是否重叠,它都可以使用。如果您不确定没有重叠,请使用memmove()
。请注意memmove()
的C标准指定(强调添加):
void *memmove(void *s1, const void *s2, size_t n);
memmove
函数将n
指向的对象中的s2
个字符复制到s1
指向的对象中。 复制发生,好像n
指向的对象中的s2
字符首先被复制到不与对象重叠的n
个字符的临时数组中由s1
和s2
指向,然后临时数组中的n
个字符被复制到s1
指向的对象中。
没有理智的memmove()
实现将数据复制到标准建议的中间数组中,除非没有可靠的方法来发现两个数组之间的重叠,这种情况很少发生。实施者知道机器的功能,几乎总能避免双重复制。
这是一个可能的代码实现,如果复制的字符串太大而无法放入目标缓冲区,则会截断该字符串。可以实现其他行为以适应应用程序设计者的想法。
#include <assert.h>
#include <stdio.h>
#include <string.h>
static void copy_substr(const char *source, const char *substr, char *buffer, size_t buflen)
{
assert(source != 0 && substr != 0 && substr[0] != '\0' && buffer != 0 && buflen != 0);
size_t length = 0;
const char *target = strstr(source, substr);
if (target != 0)
{
length = strlen(target);
if (length >= buflen)
length = buflen - 1; // length = 0 would be an option too
memmove(buffer, target, length);
}
buffer[length] = '\0'; // target might not be null terminated within length
}
int main(void)
{
char string[] = {"this is the source string to search"};
char substr[] = {"string to"};
char buffer[80];
copy_substr(string, substr, buffer, sizeof(buffer));
printf("Main string: [%s]\n", string);
printf("Substring: [%s]\n", substr);
printf("Tail string: [%s]\n", buffer);
return 0;
}
输出:
Main string: [this is the source string to search]
Substring: [string to]
Tail string: [string to search]