【问题标题】:Segmentation fault when trying to free memory尝试释放内存时出现分段错误
【发布时间】:2016-05-08 14:04:13
【问题描述】:

我有下面的代码,当我遇到分段错误时我已经评论过,什么时候没有。

最初我遇到了分段错误,然后我发现我可能无法初始化我的 char 指针位置,例如 "abcd"。但我无法理解 - 为什么?

我以为testString = "abcd"; 会将a 放在第一个内存地址,b 放在第二个,依此类推...

根据我初始化内存位置的方式,尝试释放内存时发生分段错误。

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

int main(void)
{
    char* testString = malloc(sizeof(char) * 5);

    printf("Size of char is: %d\n", sizeof(char));
    printf("Size of int is: %d\n", sizeof(int));

    for(int i = 0; i < 5; i++)
    {
        printf("Pointer addresses are: %p\n", testString + i);
    }

    char* tempPtr = testString + 2;
    printf("My temp pointer address = %p\n", tempPtr);

    // This gives me segmentation fault ....
    testString = "abcd";

    // This will not give me segmentation fault ....    
    //int count = 65;
    //for(int i = 0; i < 5; i++)
    //{
    //    testString[i] = count + i;
    //}

    printf("Printing character...\n");

    for(int i = 0; i < 5; i++)
    {
        printf("Characters are: %c\n", testString[i]);
    }

    printf("Freeing memory...\n");
    free(testString);

    //printf("Access after freeing >>%c<<\n", tempPtr[0]);
    //free(testString);
}


基于@M.M.和@Jonathan 的评论我知道testString = "abcd"; 我的testString 将指向创建字符串“abcd”的内存位置,因为我没有对其进行malloc,所以我无法释放它。此外,由于我原来指向堆内存的指针(我使用 malloc 得到的)已经消失,所以这是对内存或内存的浪费。

那么,是不是说当我使用像printf("Printing character...\n");这样的printf语句时,这也是内存泄漏呢?那我该如何避免呢?循环并插入 char* 肯定是个坏主意。

【问题讨论】:

  • testString = "abcd" 表示指针testString 现在将指向包含"abcd" 的内存位置。然后你尝试free那个位置,导致分段错误。
  • 请注意,testString = "abcd"; 会丢弃指向已分配内存的指针(内存泄漏)。也许你需要strcpy()。而且由于malloc()(或calloc()realloc())没有返回字符串文字(指针值),所以你不能释放它。
  • @l3x 我不想使用一些内置函数,想实现最基本的方法。不过感谢您的评论。
  • 发生内存泄漏是因为testString 包含指向已分配内存的唯一指针。当您分配testString = "abcd" 时,您将一个新的、不同的指针值分配给testString。您不能再释放 malloc() 返回的指针,因为您不再有它的记录。字符串"abcd" 存在于程序的内存空间中;这不是内存泄漏。导致泄漏的是指针覆盖。 printf("…") 操作不会泄漏内存。
  • 字符串"abcd" 将存在于内存中的某处。它很可能在文本段中,因为字符串文字是只读的,但标准并没有要求任何关于段的内容。不会在malloc()管理的堆区;它也可能不会在堆栈上。它很可能在数据段或文本段中——现在,在文本段中,尽管从历史上看,它本来应该在数据段中。

标签: c segmentation-fault


【解决方案1】:

这一行:

testString = "abcd";

将调用malloc() 给出的指针与字符串文字的地址重叠:"abcd" 这会导致内存泄漏,因为指向已分配内存的原始指针丢失了。

在 C 中,当复制一个字符串时,它“应该”由以下函数处理:strcpy()strncpy(),它们不会破坏包含在 testString 中的指针。

strcpy( testString, "abcd" );
strncpy( testString, "abcd", strlen( "abcd" ) );

当然,一旦分配内存的指针被赋值语句覆盖/销毁:testString = "abcd";,就不能将放入testString的新值传递给free()

段错误将在调用free() 时发生,而不是在错误分配指向testString 的新指针时发生。

【讨论】:

  • 感谢您的回答,但它并没有全面回答我的问题。
  • @hagrawal,您发布的代码中只有一行会导致内存泄漏:testString = "abcd";printf() 的调用永远不会导致内存泄漏。
【解决方案2】:

使用printf 不是内存泄漏。当一个指针通过malloc [或者,这里是strdup] 分配并且没有对应的free 调用它时,就会发生内存泄漏。

另外,试图释放一个没有被分配的指针是另一种错误。它 [可能] 不会出现段错误,但 free 会抱怨。

这是您的程序的简化版本,说明了您可以执行此操作的一些方法:

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

int opt_segv;

char *temp = "abcd";

void
dostr(char *str,int modflg)
{

    printf("\n");
    printf("dostr: %s\n",str);
    if (modflg)
        str[modflg] = 'm';
    printf("dostr: %s\n",str);
}

void
test1(void)
{
    int len;
    char *testString;

    len = strlen(temp);
    testString = malloc(len + 1);
    strcpy(testString,temp);

    dostr(testString,1);

    free(testString);
}

void
test2(void)
{
    char *testString;

    testString = strdup(temp);

    dostr(testString,2);

    free(testString);
}

void
test3(void)
{
    char *testString;

    // passing a pointer to a string _constant_ -- do _not_ modify
    testString = temp;

    dostr(testString,opt_segv ? 3 : 0);
}

int
main(int argc,char **argv)
{
    char *cp;

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 's':  // generate segfault
            opt_segv = 1;
            break;
        }
    }

    test1();
    test2();
    test3();

    return 0;
}

您可以使用-s 运行程序来模拟导致您的段错误的字符串常量修改。

【讨论】:

  • 感谢您的回答,但它并没有全面回答我的问题。如果您使用 cmets 进行了描述,或者写了一些您想从代码示例中展示的内容,那会更好。
【解决方案3】:

This question 有与我的问题的答案相关的内容,但没有详细的答案。 @Jonathan 的 cmets 回答了我所有的问题,但他没有给出详细的答案,所以我写下我的答案,以便进一步访问的人可以得到详细的解释:

我创建了一个指针并在内存的“堆段”上分配了一些空间,现在我的指针指向堆上的那个内存位置。
与所有这些相关的代码是 - char* testString = malloc(sizeof(char) * 5);

现在,当我dis this - testString = "abcd"; 然后在内存的“文本/代码段”(或在某些实现数据段)中创建字符串“abcd”并返回内存地址并分配给我的指针testString
发生的情况是,我原来指向堆上的内存位置的指针丢失了,指针开始指向内存的文本/代码段上的内存位置。

这一切的含义:

  • 它导致 内存泄漏,因为我原来指向堆内存的指针丢失了,所以现在我 无法释放该堆内存,因此内存泄漏。
  • 当我尝试使用 free(testString); 释放该内存时,我会遇到分段错误(这正是发生在我身上的事情),因为 @ 987654326@ 只能用于释放使用 malloc、calloc 或 realloc 分配的内存。现在,由于指针 testString 指向文本/代码段上的内存位置,而我没有使用某些 C 内存分配方法分配该内存,所以我无法使用 free() 释放它,如果我这样做了,我会得到分段错误。
  • 当我执行testString = "abcd"(当testString 是指针时)时,我无法访问testString 指向的内存位置,因为分配的内存在内存的文本/代码段中是只读的。所以,testString[0] = 'x' 也会导致分段错误。

当我执行printf("hello, world") 时会发生什么?:
这将在内存的文本/代码段中创建只读字符串“hello, world”。我使用size 命令验证了它确实在 C99 实现中的文本/代码段中创建。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-13
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多