2016-01-30 192 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

相關問題