繁体   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