Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
子串替换与memcpy_C_String - Fatal编程技术网

子串替换与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()
    一样。无论哪种方式,您都需要手动分配空终止符。 内存被破坏的原因很简单,因为程序读取一个字符串,但没有找到空终止符,因此将继续读取,直到它经过堆栈、堆和内存的其余部分,直到它到达空终止符(不是按该顺序)

  • 替换子字符串的方法有很多,下面是另一种稍微优雅一点的方法:

  • 编辑回应:“你能解释一下memcpy()的功能吗?为什么人们对strncpy()不满意?”

    想象一下你的记忆是这样的:

    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;
    }