簡體   English   中英

雙指針取消引用的分段錯誤

[英]Segmentation fault on double pointer dereference

以下代碼工作正常,沒有語句d = *dummy; 這是一個雙指針解引用。 但是,如果存在此行,則會發生分段錯誤。 為什么這樣?

代碼動態地為數據結構分配和初始化內存。 我試圖簡化對返回的指針指向的訪問。

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

typedef struct s_dummy {
    char dummy_number;  
} Dummy;

int mock_read_from_external_source() {
    return 4;
}

int load_dummies(Dummy** dummies, int* num_of_dummies) {
    *num_of_dummies = mock_read_from_external_source();
    *dummies = (Dummy*) calloc(*num_of_dummies, sizeof(Dummy));

    if (!dummies) {
        return 1; // allocation unsuccessful
    }

    // Iterate dummies and assign their values...

    for (int i = 0; i < *num_of_dummies; i++) {
        (*dummies + i)->dummy_number = i;
    }

    return 0;
}

void main() {
    Dummy** dummies;
    Dummy* d;
    int num_of_dummies = 0;
    int *p_num_of_dummies = &num_of_dummies;
    int err;

    err = load_dummies(dummies, p_num_of_dummies);

    // Segmentation fault occurs when dummies is dereferenced
    d = *dummies;

    if (err) {
        exit(err);
    }

    for (int i = 0; i < num_of_dummies; i++) {
        printf("Dummy number: %d\n", (*dummies + i)->dummy_number);
    }
}

提前致謝。

你因為UB而得到了錯誤,部分原因是試圖使用沒有內存的變量對象。 dummies雖然被創造為Dummies ** ,卻從來沒有提供記憶。 至少,您的編譯器應該警告您在此調用中沒有初始化的dummies

err = load_dummies(dummies, p_num_of_dummies);

只需在創建變量時初始化變量即可輕松解決此問題:

Dummy** dummies = {0}; //this initialization eliminates compile time warnings
                ^^^^^

然后是運行時錯誤。 第一個在我的系統上稱為致命運行時,這意味着操作系統由於嚴重問題而拒絕繼續,在這種情況下嘗試取消引用此行中的空指針:

dummies =(Dummy )calloc(* num_of_dummies,sizeof(Dummy));

因為你創建了一個名為dummiesDummy ** ,第一步是為指針dummies指針創建內存,然后為將產生的幾個dummies[i]實例dummies[i]創建內存。 只有這樣才能將其中任何一個成員寫入。

這是一個方法,說明如何為指針,( d )和幾個Dummies實例( d[i] )的Dummies指針創建內存:

Dummy ** loadDummies(int numPointers, int numDummiesPerPointer)
 {
     int i;
     Dummy **d = {0};
     d = malloc(numPointers * sizeof(Dummy *));//Create Dummies **
     if(!d) return NULL;
     for(i=0;i<numPointers;i++)
     {   //Now create Dummies *
         d[i] = malloc(numDummiesPerPointer*sizeof(Dummy)); //random size for illustration
         if(!d[i]) return NULL;
     }
     return d;
 }

在你的main函數中, 順便說一下它應該至少原型為: int main(void){...} ,這個版本的loadDummies可以這樣調用:

...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...

使用這個dummies集合后,請務必按照創建它們的相反順序釋放所有這些dummies 首先釋放所有dummies[0]-dummies[numPointers-1]實例,然后將指針釋放到指針, dummies

void freeDummies(Dummy **d, int numPointers)
{
    int i;
    for(i=0;i<numPointers;i++)
    {
        if(d[i]) free(d[i]);
    }
    if(d) free(d);
}

這樣稱呼:

freeDummies(dummies, 4); 

dummies從未被賦予一個值,因此取消引用會嘗試到達一些隨機內存,這幾乎肯定不會成為程序分配內存的一部分。 你應該把它分配給&d。

但你甚至不需要這樣做。 只需在調用該函數時使用&d一次。

此外,如果返回分配的假人數而不是1/0,則可以簡化代碼。 像下面的東西(未測試):

#include <stdio.h>

int mock_read_from_external_source() {
    return 10;
}

typedef struct Dummy {
    int dummy_number;
} Dummy;

int load_dummies(Dummy** dummies) {
    int want, i = 0;
    if((want = mock_read_from_external_source()) > 0) {
        *dummies = (Dummy*) calloc(want, sizeof(Dummy));
        if(*dummies) {
            // Iterate dummies and assign their values...

            for (i = 0; i < want; i++) {
                (*dummies)[i].dummy_number = i;
            }
        }
    }
    return i;
}

int main() {
    Dummy* d = NULL;
    int num_of_dummies = load_dummies(&d); // when &d is de-referenced, changes are reflected in d

    if(num_of_dummies > 0) {
        for (int i = 0; i < num_of_dummies; i++) {
            printf("Dummy number: %d\n", d[i].dummy_number);
        }
    }

    if(d) { // clean up
        free(d);
    }

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM