2016-01-30 137 views
0

我有下面的代码,当我得到分段错误时,我已经注释了,而当没有时,我已经注释了它。尝试释放内存时出现分段错误

本来我得到了分段错误,然后我可以找出可能我无法初始化我的字符指针位置,如"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。和@乔纳森的评论我明白,与testString = "abcd";testString将指向一个内存位置字符串“abcd”被创建,因为我没有malloc'ed它,我不能释放它。另外,因为我原来的堆内存指针(我使用malloc)已经不存在了,所以它浪费了内存或内存。

那么,这是否意味着当我使用像printf("Printing character...\n");这样的printf语句时,这也是内存泄漏?那我该如何避免呢?循环并插入ch​​ar *当然是一个坏主意。

+4

'testString =“abcd”'表示指针'testString'现在将指向包含'“abcd”'的内存位置。然后,您尝试“释放”该位置,导致分段错误。 –

+3

请注意'testString =“abcd”;'抛弃指向已分配内存的指针(内存泄漏)。或许你需要'strcpy()'。由于'malloc()'(或'calloc()'或'realloc()')没有返回字符串字面值(指针值),所以不能释放它。 –

+0

@ l3x我不想使用某些内置函数,并希望实现最基本的方法。感谢评论。 – hagrawal

回答

0

This question有与我的问题的答案有关的内容,但没有详细的答案。 @乔纳森的评论回答了我所有的问题,但他没有提出详细的答案,所以我正在写我的答案,以便进一步访问的人可以有详细的解释:

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

现在,当我的存款保险计划本 - testString = "abcd";然后字符串“ABCD”的内存和内存地址的“文本/代码段”(或在一些实施数据段)创建返回并分配给我的指针testString
会发生什么情况是我指向堆中的内存位置的原始指针丢失,指针开始指向内存文本/代码段上的内存位置。

蕴涵了这一切:

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

当我做printf("hello, world")会发生什么:
这将创建一个“你好,世界”字符串的内存只读文本/代码段。我证实它使用size命令在C99实现中的文本/代码段中创建。

1

这一行:

testString = "abcd"; 

被覆盖由呼叫与字符串常量的地址给malloc()指针:"abcd"这导致内存泄漏,因为原来的指针分配的内存丢失。

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

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

当然,一旦指针分配的内存已经重叠/通过赋值语句被破坏:testString = "abcd";,放入testString新的值不能传递到free()

赛格故障会发生在free()的调用中,不是错误地指定了一个指向testString的新指针。

+0

感谢您的回答,但它并未全面回答我的问题。 – hagrawal

+0

@hagrawal,在您的发布代码中只有一行导致内存泄漏:'testString =“abcd”;'调用'printf()'不应导致内存泄漏。 – user3629249

1

使用printf而不是内存泄漏。当指针通过malloc [或在此strdup]分配并且没有对应的free调用时发生内存泄漏。

另外,试图释放已分配而不是的指针是另一种类型的错误。它[可能]不会segfault,但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运行程序模拟导致你的段错误的字符串常量修改。

+0

感谢您的回答,但它并未全面回答我的问题。如果你已经描述了使用注释或者想要从代码示例中展示的内容,那么它会更好。 – hagrawal

相关问题