簡體   English   中英

C-帶結構的分段錯誤

[英]C - Segmentation fault with struct

如果這是一個容易解決的問題,我真的很抱歉,但是我是一個初學者。 我有一項工作要向堆棧結構中編寫一些函數。 結構已給出。 我無法擺脫push()行“ s-> elements ...”中的細分錯誤,不知道經過數小時的谷歌搜索之后出了什么問題。

這里的代碼:

#define STACK_SIZE 5

#include <stdio.h> #include <stdlib.h> typedef struct stackADT { int elements[STACK_SIZE]; int count; } stack; void initialize(stack *s) { stack *newStack; newStack = malloc(sizeof(*newStack)); newStack->count = 0; s = newStack; } int push(stack *s, int value) { if(s->count == 5) return -1; else { s->elements[s->count++] = value; return s->elements[s->count-1]; } } int main() { stack* sA; stack* sB; initialize(sA); initialize(sB); printf("%d\n",push(sA,3)); return 0; }

因為您要按值傳遞兩個指針(因此實際上是傳遞指針的副本),所以將初始化函數更改為int initilize(stack **s)s = newStack; *s = newStack; 然后像這樣initialize(&sA); initialize(&sB);調用initialize initialize(&sA); initialize(&sB); initialize(&sA); initialize(&sB);

除非您必須這樣做,否則您實際上不應該動態分配對象,而且您也不能free()分配的內存,這是內存泄漏。

當您將指針傳遞給函數時,該函數會收到該指針副本 除非您正在更改/創建指針的開始地址 ,否則通常這沒問題。

在您的情況下, sAsB包含地址(當您傳遞它們進行initialize時,它們是什么都沒有的指針)。 因此,您的initialize函數必須使用指針地址而不是指針本身 ,才能為指針分配一個地址,該地址將在main可見。 例如:

void initialize(stack **s)
{
    stack *newStack;
    newStack = malloc(sizeof(*newStack));
    newStack->count = 0;

    *s = newStack;
}

...

initialize (&sA);

取消引用上面的雙指針**s (例如*s = newStack; ),將newStack的地址分配為指針s的值。

我還建議在將newStack的位置分配給*s之前檢查分配是否成功:

void initialize(stack **s)
{
    stack *newStack;
    if (!(newStack = malloc(sizeof(*newStack)))) {
        fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
        exit (EXIT_FAILURE);
    }
    newStack->count = 0;

    *s = newStack;
}

我認為您需要以下內容

#include <stdio.h>

#define STACK_SIZE  5

typedef struct stackADT 
{
    int elements[STACK_SIZE];
    int count;
} stack;

void initialize( stack *s )
{
    s->count = 0;
}

int push( stack *s, int value )
{
    return s->count == STACK_SIZE ? -1 : ( s->elements[s->count++] = value );
}

int main(void) 
{
    stack sA;
    stack sB;

    initialize( &sA );
    initialize( &sB );

    printf( "%d\n", push( &sA, 3 ) );

    return 0;
}

您收到分段錯誤,因為您試圖將push()中的值分配給內存的未分配區域。 initialize()可成功分配內存並使用count = 0對其進行初始化,但是您對s = newStack分配不起作用。 正如David和Alejandro指出的那樣,您正在傳遞“指針的副本”。 本質上,您傳遞的是未初始化的stack變量的地址,但是您並未傳遞該函數用新地址更新該變量的方法。 您需要將指針傳遞給堆棧指針。 (也稱為第二級指針。)這意味着initialize()將接收包含堆棧結構的內存地址的變量的內存地址。 這樣,該函數可以將二級指針的指針的指針分配給已分配堆棧的地址。

僅僅看一下代碼,可能會更容易理解:

#define STACK_SIZE 5

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

typedef struct stackADT {
    int elements[STACK_SIZE];
    int count;
} stack;

void initialize(stack **s)
{
     stack *newStack;
     newStack = malloc(sizeof(*newStack));

     if(NULL == newStack){
        // Malloc could not allocate memory
        // for newStack.
        // Set s to NULL to indicate the error
        s = NULL;
        // Return prematurely
        return;
     } // else, malloc succeeded

     newStack->count = 0;

     // Assign the value of the malloced stack pointer to the pointee of stack **s
     *s = newStack;
}

int push(stack *s, int value)
{
    if( s->count == STACK_SIZE ){
        // Stack has too many elements.
        // Return with error value (-1)
        return -1;
    } else {
        // Assign the new value to the current last index
        s->elements[s->count] = value;
        // Add count to indicate a new variable has been added
        s->count++;
        // Use the array to return the value just added
        return s->elements[ (s->count - 1) ];
    }
}

int main()
{
    stack* sA;
    stack* sB;

    // Send the function a pointer to the stack pointer
    initialize(&sA);
    initialize(&sB);

    if(sA == NULL){
        puts("Could not allocate the memory for stack variable sA.\n");
        return -1;
    }

    printf("%d\n", push(sA, 3) );

    // Clean up the memory
    free(sA);
    free(sB);

    return 0;
}

我還稍微修改了代碼以拆分push()函數中的value分配,並添加了malloc()錯誤檢查。

注意如果您喜歡它,我建議您使用Vlad的推功能。 它更短,更簡潔; 但是,它犧牲了可讀性。 由於您是初學者,所以我決定將其擴展可能更容易理解。

暫無
暫無

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

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