การเขียนโปรแกรม C: ข้อผิดพลาด SIGABRT 134; ฉันเพิ่มหน่วยความจำนี้อย่างถูกต้องหรือไม่?

ฉันมีโครงสร้างข้อมูลที่ซ้อนกันเช่นนี้ (นี่คือการเริ่มต้น):

Interval *newInterval(int b, int e, int m){
    static Interval i;
    i.b = b;
    i.e = e;
    i.m = m;
    return &i;
}
Signal *newSignal(int size){
    static Signal s;
    s.intervals = malloc(size * sizeof(Interval));
    s.top = 0;
    s.size = size;
    return &s;
}

Stack *newStack(int size){
    static Stack st;
    st.signals = malloc(size * sizeof(Signal));
    st.top = 0;
    st.size = size;
    return &st;
}

โครงสร้างข้อมูลมีโครงสร้างอย่างไร: ตัวชี้โครงสร้างช่วงหลายช่วงจะถูกจัดเก็บไว้ในอาร์เรย์ 'ช่วง' ของโครงสร้างสัญญาณแต่ละรายการ ตัวชี้โครงสร้างสัญญาณแต่ละตัวจะถูกเก็บไว้ในอาร์เรย์ 'สัญญาณ' ของโครงสร้างสแต็ก (จะมีเพียงตัวเดียวเสมอ)

        -> [Signal 0] -> [Interval 0][Interval 1][Interval 2]...
[Stack] -> [Signal 1] -> [Interval 0][Interval 1]
        -> [Signal 2] -> [Interval 0][Interval 1][Interval 2]...

วิธีที่ฉันพยายามเข้าถึงและเพิ่มข้อมูลให้ว่าง: ฉันมีสองฟังก์ชันที่พิมพ์ข้อมูลจากภายในโครงสร้าง และพยายามเพิ่มหน่วยความจำที่จัดสรรโดยใช้ malloc (และ realloc) อย่างไรก็ตาม ดูเหมือนว่าฉันจะได้รับ SIGABRT (ข้อผิดพลาด 134) ฉันคิดว่านี่เป็นเพราะว่าฉันเพิ่มหน่วยความจำได้อย่างไร แต่ฉันไม่รู้จะทำยังไง!

    void pop(Signal *s, int n){
    if(n < s->top) {
        printf("[%d,%d)@%d ", s->intervals[n].b, s->intervals[n].e, s->intervals[n].m);
        pop(s,n+1);
    }
    else {
        free(s->intervals);
    }
}

void printIntervals(Stack *st){
    for(int i=0; i<st->top; i++){
        pop(&(st->signals[i]), 0);
        printf("\n");
        free(&(st->signals[i]));
    }
}

1. printIntervals ถูกเรียกหนึ่งครั้ง และในทางกลับกันจะเรียกฟังก์ชัน pop สำหรับแต่ละสัญญาณ

2. ฟังก์ชัน pop จะพิมพ์โครงสร้างช่วงเวลาแต่ละช่วงซ้ำๆ จนกว่าอาร์เรย์ที่มีช่วงเวลาจะว่างเปล่า ณ จุดนี้ฉันพยายามปล่อยอาร์เรย์ช่วงเวลาออกจากสัญญาณ

3. ณ จุดนี้ป๊อปอัปเสร็จสิ้น และโฟลว์จะกลับไปที่ printIntervals ที่นี่ ฉันพยายามปล่อยอาเรย์สัญญาณให้ว่างเนื่องจากไม่มีอะไรเหลือให้พิมพ์ และวงวนจะเคลื่อนไปเพื่อพิมพ์สัญญาณถัดไปจากสแต็ก

วิธีเพิ่มหน่วยความจำไม่ถูกต้องหรือไม่ ฉันจะแก้ไขข้อผิดพลาดของหน่วยความจำได้อย่างไร ขอบคุณ


person Coma    schedule 14.02.2018    source แหล่งที่มา
comment
static Stack st; ตามด้วย st.signals = malloc() แย่มาก และทำให้หน่วยความจำรั่วได้ง่าย โปรดเตรียมและทำความเข้าใจความหมายของ static ในบริบทที่คุณใช้ ดูเหมือนว่าคุณต้องการหลีกเลี่ยง malloc()ing และด้วยเหตุนี้คุณจึงทำสิ่งที่ผิดอย่างมาก   -  person Iharob Al Asimi    schedule 14.02.2018


คำตอบ (1)


หากคุณ free() ตัวชี้ Stack หลายตัว เพื่อใช้เป็นตัวทดสอบ คุณจะปล่อยตัวชี้ตัวเดียวกันเสมอ

เมื่อคุณประกาศโครงสร้างเป็น static ในขอบเขตฟังก์ชัน ระบบจะเริ่มต้นได้เพียงครั้งเดียว การเรียกครั้งต่อๆ ไปจะส่งผลต่อตัวชี้ที่คุณส่งคืนในตอนแรก ดังนั้นการใช้ malloc() กับสมาชิกหนึ่งรายจะทำให้ตัวชี้ทั้งหมดของคุณชี้ไปที่พื้นที่ malloc()ed เดียวกันอย่างมีประสิทธิภาพ ดังนั้นตัวชี้ก่อนหน้าที่มันชี้ไปตอนนี้หายไปแล้ว และคุณไม่สามารถปล่อยมันได้

ยิ่งไปกว่านั้น คุณไม่สามารถ free() สิ่งที่ไม่ได้ส่งคืนภายใน malloc() ได้ โดยเฉพาะอย่างยิ่ง เป็นเรื่องน่าสงสัยและอาจผิดที่จะเรียก free() บนตัวชี้ซึ่งอันที่จริงแล้วเป็นผลมาจากการประเมินที่อยู่ & ของตัวดำเนินการ

รหัสของคุณน่าจะได้รับการแก้ไขดังนี้

Interval *
newInterval(int b, int e, int m)
{
    Interval *interval;
    interval = malloc(sizeof(*interval));
    if (interval == NULL)
        return NULL;
    interval->b = b;
    interval->e = e;
    interval->m = m;
    return interval;
}

Signal *
newSignal(int size)
{
    Signal *signal;
    signal = malloc(sizeof(*signal));
    if (signal == NULL)
        return NULL;
    signal->intervals = malloc(size * sizeof(*signal->intervals));
    if (signal->intervals == NULL) {
        free(signal);
        return NULL;
    }
    signal->top = 0;
    signal->size = size;
    return signal;
}

Stack *
newStack(int size)
{
    Stack *stack;
    stack = malloc(sizeof(*stack));
    if (stack == NULL)
        return NULL;
    stack->signals = malloc(size * sizeof(*stack->signals));
    if (stack->signals == NULL) {
        free(stack);
        return NULL;
    }
    stack->top = 0;
    stack->size = size;
    return stack;
}

นอกจากนี้ การออกแบบที่ดีก็มีความสำคัญ และฟังก์ชันที่เรียกว่า print* จะไม่ทำให้ว่างแต่อย่างใด จริงๆ แล้วคุณควรหลีกเลี่ยงการทำให้หน่วยความจำว่างในบริบทที่กำหนดซึ่งถูกจัดสรรในบริบทอื่น

person Iharob Al Asimi    schedule 14.02.2018
comment
อีกครั้ง. คำสั่งพิเศษนั้นผิดอย่างชัดเจนที่จะ call free() บนตัวชี้ซึ่งจริงๆ แล้วเป็นผลมาจากการประเมิน & ที่อยู่ของผู้ดำเนินการ: char *p = malloc(10); free(&p[0]); จะทำงานได้ดีเช่นกัน สิ่งสำคัญไม่ใช่ที่อยู่แต่จะให้ตัวชี้ที่ถูกต้องหรือไม่ - person P.P; 14.02.2018