【问题标题】:Char Pointers and malloc字符指针和 malloc
【发布时间】:2018-02-10 10:24:58
【问题描述】:

我对 char 指针的概念有点困惑,所以我编写了一个简单的代码,只打印用户(我)提供的我的名字。我也想练习 malloc,所以我引用了指向 RAM 中某个内存的指针,但我真的不知道在 "sizeof(char) *" 后面放什么,因为那是用户输入,尚未决定。 另外,在这样做之后,我释放了内存,但我在命令行上收到一条错误消息:

*** Error in `./char': double free or corruption (fasttop): 0x00000000017fe030 ***
Aborted

好像我两次释放了相同的内存,但我不知道要删除或添加什么。请帮忙!

#include <stdio.h>
#include <cs50.h>

int main (void)
{

    char *strings = malloc(sizeof(char) * 10);


    printf("What is your name?\n");

    //wait for use to type his/her name
    strings = get_string();


    printf("Hello %s\n", strings);

    free (strings);

    return 0;
}

【问题讨论】:

  • 什么是 get_string ?是C语言定义的吗?您应该通过分配的内存来获取字符串并在那里填充数组。不覆盖。请添加get_string的代码
  • 根据cs50.stackexchange.com/questions/21617/…的回答,cs50.h的函数名是GetString()而不是get_string()
  • 运行它应该没有问题,只是内存泄漏。你是复制粘贴还是重新输入?
  • @rsp 根据CS50 reference,是get_string。我认为那张海报拼错了。
  • 为了方便大家回答问题,请将get_string 返回分配有mallocchar* 的信息添加到问题中。没有多少人会搜索 CS50 文档并进行检查。

标签: c pointers char malloc cs50


【解决方案1】:

strings = get_string(); 行实际上将get_string() 返回的值分配给strings。它不会将其写入您分配的内存中。

所以malloc() 返回的值已被覆盖(在这种情况下丢失了)。

free(strings) 正在释放 get_string() 返回的任何内容。该问题没有提供代码,但可能对free() 无效。

因为运行时告诉你它被释放了两次,我猜你已经在 get_string() 分配了内存然后释放它并返回一个无效的指针。

如果你想使用你分配的内存你需要改变get_string()来接受一个指针:

void get_string(char *str){
    //Do whatever writing you value into str[] as an array of char..
}

好的做法应该是:

void get_string(char *str, size_t max){
    //Do whatever writing you value into str[] as an array of char..
    //Use max to avoid writing beyond the end of the space allocated...
}

然后调用get_string(strings,10);

编辑:经过一番研究,该缺陷已被确定。 get_string() 不直接 free() 它返回的字符串,而是将其添加到由库进行的分配列表中,这些分配在退出时被释放(在一个名为 teardown() 的函数中注册了 atexit() 或其他编译器相关功能) .

这是一个糟糕的设计,因为没有提供消费者代码本身释放内存的安全方法,在典型的用例中,整个应用程序执行不需要这种方法。 get_double() 更糟,因为它从不返回分配的数据,但从不重复使用它,这相当于直接的内存泄漏。

代码应该:

  1. 遵守文档并要求消费者代码为free() 字符串(为清楚起见,可能将其重命名为get_string_alloc())。
  2. 提供一个库例程来释放字符串(get_new_string()release_string()

在 C 中没有很好的方法来转移分配内存的所有权,但在剩余的执行过程中保留它绝对不是答案。 许多图书馆四处走动,将分配推送到消费者代码上,但是当无法知道所需空间的完整大小时,这很繁重。

我建议将_alloc() 放在任何返回对象的函数的末尾,消费者代码稍后必须free()

因此,所提出问题的答案是删除malloc()free(),因为库处理这两者。但是请注意,如果您的程序多次调用该函数以及其他内部依赖它的函数(如 get_double()),您可能会因为库处于死区而耗尽内存。

【讨论】:

  • “大概 free() 它是无效的。” -unfortunately, it is valid。我仍然怀有最大的愿望来扼杀设计 cs50.h 库的恶魔,原因有多种,包括但不限于 typedef char *string; 那里应该告诉你这个标题是多么的无耻。
  • @WhozCraig 那么我认为cs50代码可能有问题。你不应该这样做 malloc() 因为 docco 说它分配了空间。但仅仅因为你的代码泄漏了 10 个字节,不应该导致一条消息说你已经双重释放了一些东西。它可能只是在执行结束时发出一个错误,即未释放 10 个字节的块。你从哪里得到代码?你能发布get_string()的来源吗?
  • 显然,取决于您使用的 cs50 版本,library may manage its own chain of heap allocations from get_string,并在进程退出时释放它们(对于良好做法毫无意义的保存,因为操作系统无论如何都会回收所有内存)。在这样做时,如果在用户代码中也这样做,肯定会出现双重释放。不同版本的库不会这样做。因此,遵循旧教程的人会编写代码,使用较新的库会导致双重释放。这可能就是这里发生的事情。
  • @WhozCraig 我在 github 上四处寻找,看到一个版本这样做。这是疯狂。你有义务使用这个吗?
  • 不幸的是,一些从学校学习课程的学生选择使用该库作为其入门课程的一部分,他们不得不使用它。这也太糟糕了,因为这个“有用的”库所做的许多事情都是优秀的补救候选人,作为被教授语言的人的任务。严重地。 get_intget_string 等都是人们学习语言和标准库的有价值的方式。
【解决方案2】:

问题是您的get_strings 覆盖了您最初的malloc。指针值是一个值。通过将其等同于其他东西,您替换了您的malloc 值。

【讨论】:

    【解决方案3】:

    内存分配在语句:
    strings = get_string();

    你不必malloc它(char *strings = malloc(sizeof(char) * 10); )

    没有malloc 也可以正常工作

    【讨论】:

      【解决方案4】:

      首先你创建了一个动态内存,它会被 *strings 指向。但是随后您使用 *strings 指针指向本地字符串(来自 get_string() 函数)。当您调用 free 时,程序正在尝试删除本地(堆栈)引用并抛出错误。

      要解决这个错误,程序应该是

      #include <stdio.h>
      #include <cs50.h>
      
      int main (void)
      {
      
      char *strings = malloc(sizeof(char) * 10);
      
      
      printf("What is your name?\n");
      
      //wait for use to type his/her name
      strcpy(strings, get_string());       // Use strcpy instead of assigning
      
      
      printf("Hello %s\n", strings);
      
      free (strings);
      
      return 0;
      }
      

      【讨论】:

        【解决方案5】:

        您没有包含get_string() 的代码,但是您使用错误的返回值覆盖了strings。您传递给free() 的地址必须来自malloc(),并且您似乎违反了这一点(除了丢失您的10 个字节的原始返回地址)。

        假设 get_string() 返回静态存储(即您不需要释放它),您可以在不涉及 malloc() 的情况下执行此操作。

        如果你真的想要,这样的事情可能会奏效:

        printf("What is your name?\n");
        const char *name = get_string();
        const size_t nlen = strlen(name);
        char * const name_copy = malloc(nlen + 1);
        if(name_copy != NULL)
        {
          memcpy(name_copy, name, nlen + 1);
          printf("Hello %s (from my own memory!)\n", name_copy);
          free(name_copy);
        }
        

        这是相当复杂的,但你明白了。

        【讨论】:

        • 假设是错误的:get_string 返回调用者必须释放的内存。您可以简单地将strdup 用于复制部分。 ;)
        【解决方案6】:

        char *strings;

        • 不需要新的 malloc,因为从 get_string() 函数返回的字符串已经在堆上,您只需要获取指向第一个字符的指针。 (get_string() function reference)

        strings = get_string();

        printf("Hello %s\n", 字符串);

        • 打印字符串后,您应该释放为其分配的内存,如 get_string() 函数参考中所述

        在堆上存储字符串(通过 malloc);调用者必须释放内存 避免泄漏。

        我认为其他一切都很好,试试这个代码:

        #include <stdio.h>
        #include <cs50.h>
        
            int main (void)
            {
                char *strings;
        
                printf("What is your name?\n");
        
                //wait for use to type his/her name
                strings = get_string();
        
                printf("Hello %s\n", strings);
        
                free (strings);
        
                return 0;
            }
        

        【讨论】:

        • 我同意 malloc 不需要并导致内存泄漏。但这怎么会导致错误消息“double free”?
        • @Gerhardh 问题是编译器遇到了麻烦,因为他覆盖了指针 char *strings = malloc(sizeof(char) * 10);从这个 malloc 中得到 get_string() 返回指针值,所以他自动丢失了一个用于释放他最初 malloc 的指针,现在它没有被释放。
        • 我知道,但内存泄漏基本上与“双重释放或损坏”错误通常表示的相反。错误消息表明某些内存被释放了两次或内存边界被覆盖。该错误消息与该内存泄漏不匹配。一定有别的东西。鉴于这段代码很短,这很奇怪......
        • 在那个 Q 中,OP 确实写到了分配内存的末尾。这显然是那里的原因。在此 Q 中,该缓冲区中没有写入。
        猜你喜欢
        • 2014-04-12
        • 2010-11-10
        • 2020-04-08
        • 1970-01-01
        • 1970-01-01
        • 2012-12-11
        • 2013-05-18
        • 1970-01-01
        • 2016-07-05
        相关资源
        最近更新 更多