c - 使用动态分配的内存替换字符串

标签 c replace

我正在使用下面的函数来替换给定字符串中的子字符串

void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
    char *result = NULL;
    int i, cnt = 0;
    int tolen = strlen(to);
    int fromlen = strlen(from);

    if (*inputString == NULL)
        return;

    // Counting the number of times old word
    // occur in the string
    for (i = 0; (*inputString)[i] != '\0'; i++)
    {
        if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
        {
            cnt++;

            // Jumping to index after the old word.
            i += fromlen - 1;
        }
    }

    // Making new string of enough length
    result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
    if (result == NULL)
        return;

    memset(result, 0, i + cnt * (tolen - fromlen) + 1);

    i = 0;
    while (&(*inputString))
    {
        // compare the substring with the result
        if (strstr(*inputString, from) == *inputString)
        {
            strncpy(&result[i], to, strlen(to));
            i += tolen;
            *inputString += fromlen;
        }
        else
        {
            result[i++] = (*inputString)[0];
            if ((*inputString)[1] == '\0')
                break;
            *inputString += 1;
        }
    }

    result[i] = '\0';
    *inputString = result;
    return;
}

上述函数的问题是内存泄漏。在此行之后,为 inputString 分配的任何内存都将丢失。

*inputString = result;

因为我正在使用 strstr 并移动 inputString 的指针 *inputString += fromlen; inputString 在上一行之前指向 NULL。那么这里如何处理内存泄漏。

注意:我不想返回函数内部分配的新内存。我需要根据新长度更改 inputString 内存。

最佳答案

您应该使用局部变量来遍历输入字符串,并避免在释放前一个字符串并将其替换为新分配的指针的最后一步之前修改 *inputString

使用当前的 API,必须使用指向用 malloc() 或类似方法分配的 block 的指针地址调用 ReplaceSubStr。将指针传递给本地存储或字符串文字将具有未定义的行为。

这里有一些改进的想法:

  • 您可以返回新字符串并将其留给调用者以释放前一个字符串。在这种情况下,您将按值而不是按地址获取输入字符串:

    char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
    
  • 如果 from 字符串为空,您应该在输入字符串的每个字符之间插入 to 字符串,或者什么都不做。正如发布的那样,您的代码对于这种边界情况有未定义的行为。

  • 要检查 from 字符串是否出现在偏移量 i 处,请使用 memcmp 而不是 strstr
  • 如果cnt为0,则无事可做。
  • 您应该为调用者返回错误状态以确定是否可以分配内存。
  • 不需要初始化result数组。
  • 避免使用 strncpy()。此功能具有违反直觉的语义,并且经常被误用。读这个:https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

这是一个改进的版本:

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

int ReplaceSubStr(char **inputString, const char *from, const char *to) {
    char *input = *inputString;
    char *p, *q, *result;
    size_t cnt;
    size_t tolen = strlen(to);
    size_t fromlen = strlen(from);

    if (input == NULL || fromlen == 0)
        return 0;

    // Counting the number of times old word occurs in the string
    for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
        p += fromlen;
    }
    if (cnt == 0)   // no occurrence, nothing to do.
        return 0;

    // Making new string of enough length
    result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
    if (result == NULL)
        return -1;

    for (p = input, q = result;;) {
        char *p0 = p;
        p = strstr(p, from);
        if (p == NULL) {
            strcpy(q, p0);
            break;
        }
        memcpy(q, p0, p - p0);
        q += p - p0;
        memcpy(q, to, tolen);
        q += tolen;
        p += fromlen;
    }
    free(*inputString);
    *inputString = result;
    return 0;
}

int main() {
    char *p = strdup("Hello world!");
    ReplaceSubStr(&p, "l", "");
    printf("%s\n", p);  // prints Heo word!
    free(p);
    return 0;
}

关于c - 使用动态分配的内存替换字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50268903/

相关文章:

c - 将波形文件数据加载到缓冲区

powershell - PowerShell 的正则表达式无法与/n(换行符)一起使用

javascript - 正则表达式替换和追加字符串

r - 使用 for 循环将交易列表中的值放入稀疏矩阵中

c - 如何获得套接字的稳定主机名?

c++ - int(*a)的解释[3]

c - 如何获取指向动态库(Linux ELF)特定部分的指针?

ruby - 用另一个字符替换 Ruby 中的字符

javascript - 从文本中删除文本和数字

c - 为什么编译器不能导出字符串数组的字符串长度?