【问题标题】:C char array concatenation memory dumpedC char 数组串联内存转储
【发布时间】:2016-04-15 15:47:56
【问题描述】:

我有以下代码:

char * set_number(void)
{
    // char * sname = malloc(sizeof(char) * 18); Original
    char * sname = malloc(sizeof(char) * 19); // After EDIT 1
    memset(sname, '\0', 19);                  // After EDIT 1
    strcat(sname, "0x0012345678912345");
    return sname;
}

char * get_number(void)
{
    char * rnumber = set_number();
    return rnumber;
}

char * work_with_number(void)
{
    int i = 7;
    char * wnumber = get_number();
    if(strstr(wnumber, "0x00") != NULL)
    {
        wnumber += 4;
        char c = i + '0';
        // Would like to concatene c at the end of wnumber here
    }
    return wnumber;
}

int main(int argc, char **argv)
{
    char * str = work_with_number();
    fprintf(stdout, "str : %s\n", str);
    return 0;
}

返回:

str : 12345678912345

正如评论中所写,我想将c 连接到wnumber

但是,使用 strcat() 会导致内存转储。

另外内存需要释放到主函数中,不是吗?

我想我还是误解了这里的逻辑。

【问题讨论】:

  • 除了 Sourav 说的:在 wnumber 上加 4 理论上很好,但现在你不知道调用 work_with_number 后要释放哪个内存。
  • 那么,您是否建议创建另一个缓冲区str = (char *) malloc(strlen(sname) 来存储字符串&sname[4]
  • 是的,但可能是str = malloc(strlen(sname) + 2)。您需要一个字符作为空终止符,一个字符作为要附加的“7”字符。另外,您不应该在 c 中转换 malloc 的返回值。

标签: c arrays pointers concatenation dynamic-memory-allocation


【解决方案1】:

在我看来,问题是

  • malloc() 不返回 null 初始化的内存块,strcat() 期望第一个参数以 null 结尾。
  • 如果要将数组用作字符串,还需要为空终止符分配内存。

所以,

  1. 在为sname 分配内存时,为保持空终止符分配空间。
  2. 使用strcpy() 将字符串复制到sname。否则,如果你想继续使用strcat(),你可以调用calloc(),它返回0填充的内存。
  3. 您只能在malloc() 和家人返回的原始指针上调用free()。如果您打算移动实际指针,则需要在某处保留原始指针的副本,以便稍后传递给free()

【讨论】:

  • 感谢您的可靠回答,主要帖子已根据您的第一个注释交换。但是,在第二点 strcpy() 创建内存转储时,我仍然面临同样的问题。
  • @SnP 您没有足够的空间将任何内容连接到原始字符串。
【解决方案2】:

如果您的字符串以0x00 开头,您希望删除该前缀并附加一个 7。您的方法存在几个问题,其中许多问题已经被其他人解决:

  • 您必须按住从malloc 收到的指针,以便稍后free 内存。
  • 字符串末尾没有空间可以连接任何内容。
  • strstr 在字符串中的任意位置查找搜索字符串,但您想测试 0x00 是否在开头。为此请使用 strncmp
  • strcat 连接到以零结尾的字符串,但是先将内存归零然后strcatting 是浪费的。 strcpy 直接转字符串。

另一种方法是将字符串的其余部分移到前面。这将在最后留下四个字符,您可以使用它们来附加内容,但当然不会超过您删除的内容:

before:    0 x 0 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 \0
                   |                         |
           +-------+                 +-------+
           |                         |
after      1 2 3 4 5 6 7 8 9 1 2 3 4 5 7 \0
                                       |  |
                                       +--+---- new

您可以为此编写一个循环,但标准库中也有两个函数用于此:memcpy,要求缓冲区不重叠,memmove,可以处理重叠缓冲区。你需要memmove

所以:

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

char *get_number(void)
{
    char *sname = malloc(19);

    if (sname) strcpy(sname, "0x0012345678912345");
    return sname;
}

char *work_with_number(void)
{
    char *wnumber = get_number();

    if(strncmp(wnumber, "0x00", 4) == 0) {
        size_t len = strlen(wnumber + 4);       // length of rest of str

        memmove(wnumber, wnumber + 4, len);     // move rest to front
        wnumber[len++] = '7';                   // append digit seven
        wnumber[len++] = '\0';                  // append null terminator!
    }

    return wnumber;
}

int main(int argc, char **argv)
{
    char *str = work_with_number();

    fprintf(stdout, "str : %s\n", str);         // user str
    free(str);                                  // free it after use

    return 0;
}

【讨论】:

  • 不错的解决方案 +1。不过我更喜欢malloc(strlen("0x0012345678912345") + 1)。而第二个len++ 并不是真正需要的。
  • 感谢您的回答。最后一个问题,如果7 必须由其他接受指针作为参数的函数计算,尤其是wnumber,附加什么。指针wnumber 始终包含 345 作为最后三位数字,这可能会产生错误。是否与 memmove 等价,它首先将内存归零?
  • 只要有效字符的范围以零结尾,就不需要将任何内容归零。您可以拥有一个大小为 100 的 char 缓冲区,其中包含一个空终止符,后跟 99 个 garnage 字符。这是空字符串的有效表示。如果你想在移动字节之后将间隙中的四个字节归零,你可以使用memset(str + len, 0, 4),但这就像在拆掉它之前清理和粉刷你的房子。
猜你喜欢
  • 2017-10-30
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多