子串替换与memcpy
根据这个问题中的建议,我编写了以下程序来查找并替换字符串中的目标子字符串。(它可以在一个循环中运行,使用子串替换与memcpy,c,string,C,String,根据这个问题中的建议,我编写了以下程序来查找并替换字符串中的目标子字符串。(它可以在一个循环中运行,使用strstr()string方法查找并替换“target”的所有实例,但这里我只给出一个示例。) #包括 #包括 #定义成功1 #定义故障0 #定义STR_CAP 80+1 int stringify(字符*字符串、常量字符*目标、常量字符*替换){ 字符段[STR_CAP]; int S=strlen(字符串),T=strlen(目标); 字符前置段[STR_CAP]; 字符后置段[STR_
strstr()
string方法查找并替换“target”的所有实例,但这里我只给出一个示例。)
#包括
#包括
#定义成功1
#定义故障0
#定义STR_CAP 80+1
int stringify(字符*字符串、常量字符*目标、常量字符*替换){
字符段[STR_CAP];
int S=strlen(字符串),T=strlen(目标);
字符前置段[STR_CAP];
字符后置段[STR_CAP];
对于(int i=0;i
但有些事情我不明白
(1) 首先:在我使用memcpy()
并手动设置复制到'\0'
的字符串的结尾之前,我不断收到缓冲区溢出(以堆栈崩溃的形式)和奇怪的错误。这会有什么影响,而仅仅简单地使用strncpy()
却没有?例如,如果你注释掉“神奇”一行,程序就要内爆了
(2) 有没有更好或更规范的方法?这感觉很笨拙,但我找不到任何关于子字符串替换的基本“操作方法”
memcpy()strncpy()
仅当在n个字符中找到空终止符时,才会复制前n个字符,并用0(空终止符)填充其余的字符,因此您很有可能给了strncpy()
要复制的字符串的长度,但没有找到空终止符。从这个意义上讲,strncpy()
的行为就像memcpy()
一样。无论哪种方式,您都需要手动分配空终止符。
内存被破坏的原因很简单,因为程序读取一个字符串,但没有找到空终止符,因此将继续读取,直到它经过堆栈、堆和内存的其余部分,直到它到达空终止符(不是按该顺序)
0 3
01 | 30 | 40 | 00 | 32 | 40
0 3
01 | 30 | 40 | 01 | 30 | 40
然后我执行memcpy(0x03,0x00,3)代码>告诉计算机将3个字节从地址0复制到地址3。现在我的记忆是这样的:
0 3
01 | 30 | 40 | 00 | 32 | 40
0 3
01 | 30 | 40 | 01 | 30 | 40
计算机完全按照我的指示逐字节复制。让我们看看strncpy()
在这种情况下会做什么。从上面的第一个图开始,调用strncpy(0x03,0x00,3)代码>告诉计算机将0x00处以null结尾的字符数组(字符串)复制到0x03,但最大值为3个字符。结果是:
0 3
01 | 30 | 40 | 01 | 30 | 40
让我们想象一下,我们从以下几点开始:
0 3
65 | 00 | 40 | 01 | 30 | 40
这里,地址0x00实际上是指一个1个字符长的字符串:“a”。
现在,如果我们调用相同的strncpy(0x03,0x00,3)
计算机首先复制65,注意到一个空终止符,并在那里停止。然后用0填充其余部分,结果如下:
0 3
65 | 00 | 40 | 65 | 00 | 00
您可以看到,如果字符串长度超过3个字符,strncpy
不会为您复制空终止符,因为它将“最大输出”。这与memcpy
相同strncpy
仅当在前n个字节中遇到空终止符时,才会将空终止符移动到目标。因此,您可以在前几个示例中看到,即使地址0x00包含一个3个字符的有效字符串(在地址0x03处以0结尾),函数strncpy()
没有在目标(0x03)处生成有效字符串,因为0x04可以是任何东西(不一定是空终止符) memcpy()
只需将大量字节从一个数组复制到另一个数组。这是一个非常简单的函数,有两个注意事项:
- 当源阵列和目标阵列重叠时,不应使用它
- 这意味着要复制字节,因此必须将大小计算为字节数,这在较大类型的数组之间复制时很容易出错。在本例中,
char
类型根据定义正好是一个字节,因此大小只是字符数,如果需要,加上空终止符1
memmove()
的作用与memcpy
相同,但它可以用于重叠对象。它需要额外的测试来正确处理所有情况
使用这些函数,下面是一个更简单的stringify
函数版本:
#include <stdio.h>
#include <string.h>
int stringify(char *dest, const char *target, const char *replace) {
char *p = strstr(dest, target);
if (p == NULL) {
/* no replacement */
return 0;
}
size_t len1 = strlen(target);
size_t len2 = strlen(replace);
if (len1 != len2) {
/* move the remainder of the string into the right place */
memmove(p + len2, p + len1, strlen(p + len1) + 1);
}
memcpy(p, replace, len2);
return 1;
}
int main(void) {
char string[80] = "The quick brown fox jumped over the lazy, brown dog.";
char target[] = "brown";
char replacement[] = "ochre-ish";
stringify(string, target, replacement);
printf("%s\n", string);
stringify(string, target, replacement);
printf("%s\n", string);
return 0;
}
您的方法有一个很大的问题:替换
可能足够长
结果字符串的长度将超过80个字符
我愿意这样做
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *stringify(const char *src, const char *target, const char *replacement)
{
int buffer_len = 0;
char *buffer = NULL, *tmp;
if(src == NULL || replacement == NULL || target == NULL)
return NULL;
int repl_len = strlen(replacement);
int target_len = strlen(target);
while(tmp = strstr(src, target) && target_len)
{
// get length of string until target
int substr_len = tmp - src;
// get more space
char *new_buff = realloc(buffer, buffer_len + substr_len + repl_len + 1);
if(new_buff == NULL)
{
// out of memory
return buffer;
}
if(buffer == NULL) // first realloc
*new_buff = 0;
buffer = new_buff;
// copy that what is before the found target
strncat(buffer, src, substr_len);
buffer[buffer_len + substr_len] = 0;
//// copy the replacement at the end of buffer
strncat(buffer, replacement, repl_len);
buffer[buffer_len + substr_len + repl_len] = 0;
buffer_len += substr_len + repl_len;
//// set src to the next character after the replacement
src = tmp + target_len;
}
if(buffer == NULL) // target never found
{
buffer = malloc(strlen(src) + 1);
if(buffer == NULL)
return NULL;
strcpy(buffer, src);
} else {
if(*src) {
// copy the leftover
int leftover_len = strlen(src);
char *new_buff = realloc(buffer, buffer_len + leftover_len + 1);
if(new_buff == NULL)
return buffer; // could not expand more, return all we've converted
buffer = new_buff;
strcat(buffer, src);
}
}
return buffer;
}
int main(void)
{
char string[] = "The quick brown fox jumped over the lazy, brown dog.";
char target[] = "brown";
char replacement[] = "ochre-ish";
char *new_txt = stringify(string, target, replacement);
if(new_txt)
{
printf("new string: %s\n", new_txt);
free(new_txt);
} else
printf("Out of memory\n");
return 0;
}