【问题标题】:Dynamic memory allocation + truncating a string issue动态内存分配 + 截断字符串问题
【发布时间】:2010-01-06 13:38:23
【问题描述】:

我一直在玩弄 malloc、realloc 和 free,以便编写一些基本函数来操作 C 字符串 (char*)。从字符串中删除最后一个字符时,我遇到了这个奇怪的问题。我用这样的原型写了一个函数:

int string_erase_end (char ** dst, size_t size);

它应该将“dst”字符串缩短一个字符。到目前为止,我已经想出了这个代码:

int string_erase_end (char ** dst, size_t size)
{
    size_t s = strlen(*dst) - size;
    char * tmp = NULL;
    if (s < 0) return (-1);
    if (size == 0) return 0;
    tmp = (char*)malloc(s);
    if (tmp == NULL) return (-1);
    strncpy(tmp,*dst,s);
    free(*dst);
    *dst = (char*)malloc(s+1);
    if (*dst == NULL) return (-1);
    strncpy(*dst,tmp,s);
    *dst[s] = '\0';
    free(tmp);
    return 0;
}

在 main() 中,当我截断字符串时(是的,我之前对它们调用了 malloc),我得到了奇怪的结果。根据我要截断的字符数,它可以正常工作、截断错误数量的字符或引发分段错误。

我没有动态内存分配的经验,并且一直使用 C++ 及其 std::string 来完成所有这些肮脏的工作,但这次我需要在 C 中完成这项工作。如果有人帮助我找到我将不胜感激并在这里纠正我的错误。提前致谢。

【问题讨论】:

    标签: c string malloc truncation


    【解决方案1】:

    第一个 strncpy() 没有在 tmp 的末尾放置一个 '\0'。

    另外,您可以避免重复复制:*dst = tmp;

    【讨论】:

    • 顺便说一句,if (s
    • 谢谢,它现在可以完美运行了。下次我会记得考虑到 '\0' 字符。
    • 问题在于 strncpy 的奇怪语义。我认为这是回到 Unix 目录条目最多 14 个字符的时代,如果正好有 14 个字符,则非 nul 终止。
    • 确实,我注意到在 strncpy 的描述中,如果复制的字符数小于源字符串的长度,它不会复制最终的 nul 字符...
    【解决方案2】:

    根据您的描述,您的函数应该删除字符串中的最后 n 个字符:

    /* Assumes passed string is zero terminated... */
    void string_erase_last_char(char * src, int num_chars_to_erase)
    {
        size_t len = strlen(src);
    
        if (num_chars_to_erase > len)
        {
            num_chars_to_erase = len;
        }
    
        src[len - num_chars_to_erase] = '\0';
    } 
    

    【讨论】:

    • 是的,我相信这是最简单的方法。不过,我暂时将使用内存(重新)分配,因为我需要习惯它的工作方式。不过还是谢谢你的建议,以后会有用的。
    【解决方案3】:

    我不明白size 参数的用途。

    如果您的字符串最初是使用malloc() 分配的,您应该只使用realloc() 来更改它们的大小。这将自动保留内容,并且需要更少的操作:

    int string_erase_end (char ** dst)
    {
      size_t len;
      char *ns;
    
      if (dst == NULL || *dst == NULL)
       return -1;
    
      len = strlen(*dst);
      if (len == 0)
        return -1;
    
      ns = realloc(*dst, len - 1);
      if (ns == NULL)
       return -1;
      ns[len - 1] = '\0';
      *dst = ns;
    
      return 0;
    }
    

    在“现实世界”中,您通常不会更改 1 字符截断的分配大小;这太低效了。您将改为单独跟踪字符串的长度及其分配的大小。这使得字符串很容易增长;只要已经分配了空间,追加一个字符是非常快的。

    此外,在 C 中,您永远不需要转换 malloc() 的返回值;它没有任何用途,并且可以隐藏错误,所以不要这样做。

    【讨论】:

    • 感谢您提供有用的提示,放松一下。我之前尝试过 realloc,但是每当减小字符串的大小时都会出现分段错误(而附加到字符串可以使用 realloc)。我不知道为什么。
    猜你喜欢
    • 2018-06-16
    • 1970-01-01
    • 1970-01-01
    • 2011-01-19
    • 2022-01-22
    • 2019-09-06
    • 2018-05-18
    相关资源
    最近更新 更多