c - 替换 C 字符字符串中的字符串(strreplace,无 sprintf)

标签 c string malloc realloc strncpy

你好,很抱歉,如果这个问题已经得到回答(以我想要的方式:-)),但我想我有内存问题。
假设以下 C 函数(是的,这个很脏而且没有优化):

char *strreplace(char **str, char *dst, char *replace) {
    int replacestart = stringcompare(*str, dst), replaceend = strlen(dst), replacelen = strlen(replace);
    char *tmp1 = (char *)malloc(sizeof(char) * (replacestart + 1)), *tmp2 = (char *)malloc(sizeof(char) * ((strlen(*str) - replaceend) + 1));

    memset(tmp1, 0, sizeof(char) * (replacestart + 1));
    memset(tmp2, 0, sizeof(char) * ((strlen(*str) - replaceend) + 1));
    strncpy(tmp1, *str, replacestart);
    strncpy(tmp2, *str + replacestart + replaceend, (strlen(*str) - (replaceend + replacestart)));

    *str = realloc(*str, strlen(tmp1) + replacelen + strlen(tmp2));
    memset(*str, 0, strlen(tmp1) + replacelen + strlen(tmp2));

    strncpy(*str, tmp1, strlen(tmp1));
    strncpy(*str + strlen(tmp1), replace, replacelen);
    strncpy(*str + strlen(tmp1) + replacelen, tmp2, strlen(tmp2));
    return *str;
}

如上所示,它应该用 *replace 替换 **str 中的 *dst
这基本上按预期工作。问题是:

输出 (*str) 在 memsetting 之后没有被零清除,并且仍然有错误的长度,即使在重新分配之后也是如此。
意思是,如果字符串在替换后较长,则 *str 的最后一个字符会被截断。
反过来,如果字符串较短,则会找到位于 char 字符串末尾的旧字符。

我做错了什么。提到我不想使用 sprintf 也不想使用 C++-STL,只想用 C 中的指针来实现。

换句话说,用指针替换 c 字符字符串中的字符串的正确方法是什么。

非常感谢。

请求更多信息后编辑

我使用这个函数如下:

...open a textfile via FILE type, determining file lengts (fseek)...

char *filecontent = (char *)malloc(sizeof(char) * filesize);
if(filesize != fread(filecontent, sizeof(char), filesize, fd)) {
    free(filecontent);
    return -1;
}

streplace(&filecontent, "[#TOBEREPLACED#]", "replaced");

...doing other stuff with filecontent...

编辑 2,添加 stringcompare()

int stringcompare(const char *string, const char *substr) {
    int i, j, firstOcc;
    i = 0, j = 0;

    while(string[i] != '\0') {
        while(string[i] != substr[0] && string[i] != '\0') {
            i++;
        }
        if(string[i] == '\0') {
            return -1;
        }

        firstOcc = i;

        while(string[i] == substr[j] && string[i] != '\0' && substr[j] != '\0') {
            i++;
            j++;
        }
        if(substr[j] == '\0') {
            return firstOcc;
        }
        if(string[i] == '\0') {
            return -1;
        }

        i = firstOcc + 1;
        j = 0;
    }
}

最佳答案

函数的逻辑并不像乍看起来那么简单。

您应该决定在 1) 源字符串为空和 2) 目标字符串为空时执行什么操作。

例如,如果目标字符串为空,则标准函数 strstr 将返回源字符串第一个字符的地址。然而逻辑上,如果 dst 是一个空字符串,那么源字符串不应该被改变,除非它反过来是一个空字符串。在这种情况下,该函数应该只创建一个等于字符串 replace 的新字符串。

考虑到字符串 dstreplace 在函数中没有改变,它们应该用限定符 const 声明。

char * strreplace( char **str, const char *dst, const char *replace );

此外,该函数还应在分配失败的情况下通过返回空指针来报告新内存分配是否成功。

考虑到所有这些因素,该函数可以看起来像演示程序中所示的以下方式。

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

char * strreplace( char **str, const char *dst, const char *replace )
{
    char *result = *str;

    if ( *str[0] == '\0' )
    {
        if ( dst[0] == '\0' && replace[0] != '\0' )
        {
            char *result = malloc( strlen( replace ) + 1 );

            if ( result )
            {
                strcpy( result, replace );
                free( *str );
                *str = result;
            }
        }
    }
    else if ( dst[0] != '\0' )
    {
        char *pos = strstr( *str, dst );

        if ( pos != NULL )
        {
            size_t dst_n = strlen( dst );
            size_t replace_n = strlen( replace );

            result = ( char * )malloc( strlen( *str ) - dst_n + replace_n + 1 );

            if ( result )
            {
                size_t n = pos - *str;

                strncpy( result, *str, n );
                strcpy( result + n, replace );
                strcpy( result + n + replace_n, *str + n + dst_n );
            }

            free( *str );
            *str = result;
        }
    }


    return result;
}

int main(void) 
{
    const char *hello = "Hello everybody here";
    char *str = malloc( sizeof( char ) );
    str[0] = '\0';

    if ( strreplace( &str, "", hello ) )
    {
        puts( str );
    }

    if ( strreplace( &str, "everybody", "Eurobertics" ) )
    {
        puts( str );
    }

    if ( strreplace( &str, "Hello", "Bye" ) )
    {
        puts( str );
    }

    if ( strreplace( &str, " here", "" ) )
    {
        puts( str );
    }

    if ( strreplace( &str, "Bye ", "" ) )
    {
        puts( str );
    }

    free( str );

    return 0;
}

程序输出为

Hello everybody here
Hello Eurobertics here
Bye Eurobertics here
Bye Eurobertics
Eurobertics

关于c - 替换 C 字符字符串中的字符串(strreplace,无 sprintf),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48366110/

相关文章:

c - 进程在 C 中返回 -1073741819 (0xC0000005)

c - 当/dev/ttyUSB* 出现时打开它

c - 取消共享挂载命名空间未按预期工作

c - 以下哪一种是设置无符号整数最大值的更便携的方法?

c# - 如何从路径中提取文件名

Python - 多个 %s 字符串

c - 将c代码执行结果写入txt

java - 如何在不删除分割字符的情况下分割字符串

c - malloc 与数组,无法理解为什么这有效

c - malloc.c :3096: SYSMALLOC: Assertion failed