从堆栈读取时出现分段错误

时间:2019-10-30 02:09:01

标签: c stack

这是我第一次创建堆栈。我很清楚我必须做什么,但是由于代码无法正常工作而感到沮丧。

运行正常,直到我尝试从根目录检索任何数据,这立即导致段错误。

这是我的程序:

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

struct stackNode
{
    char letter;
    struct stackNode * next;    
};

int size=0;
int capacity=10;

struct stackNode * root=NULL;

void push(char data, struct stackNode * root)
{
    if(size==capacity)
    {
        printf("Error: Stack Overflow\n");
        return;
    }

    struct stackNode * new=(struct stackNode *)malloc(sizeof(struct stackNode *));
    new->letter=data;
    new->next=root;
    printf("%c,%u", new->letter, new->next);
    root=new;
    printf("%c,%u", new->letter, new->next);
    size++;
}

char pop(struct stackNode ** root)
{
    if(size==0)
    {
        printf("Error: Stack is Empty\n");
        return '\0';
    }

    printf("\npop*\n");

    char temp;
    printf("\n*\n");
    struct stackNode * tempad;
    printf("\n*\n");
    temp=(*root)->letter;
    printf("\n*\n");
    tempad=*root;
    printf("\n*\n");
    *root=(*root)->next;
    printf("\n*\n");
    free(tempad);
    printf("\n*\n");
    size--;
    return temp;
}

int main()
{
    push('c', root);
    push('v', root);
    push('n', root);

    printf("%c %c %c", pop(&root), pop(&root), pop(&root));
}

以下是输出:

pop*

*

*
Segmentation fault

有人可以指出错误吗?

2 个答案:

答案 0 :(得分:1)

这确实是令人困惑的代码(即,与局部作用域中的变量同名的全局变量)。我只是要重写它,未经测试并且可以在移动设备上使用,但应该没问题。您可以进行比较以查看问题。一方面,尽管您将局部变量root设置为最新的分配,而不是全局根。

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

struct stackNode
{
    char letter;
    struct stackNode* prev;    
};

stackNode* kTailStack = NULL;

void push(char data)
{
    stackNode* p=(stackNode *)malloc(sizeof(stackNode));
    p->letter=data;
    p->prev=kTailStack;
    kTailStack = p;
}

char pop()
{
    stackNode* prev_tail = kTailStack;
    char n = 0;

    if (prev_tail != NULL)
    {
        n = prev_tail->letter;
        kTailStack = prev_tail->prev;
        free(prev_tail);
    }

    return n;
}

int main()
{
    push('c', kTailStack);
    push('v', kTailStack);
    push('n', kTailStack);

    printf("%c %c %c", pop(kTailStack), pop(kTailStack), pop(kTailStack));
}

答案 1 :(得分:1)

主要问题是使用不必要的全局变量,这似乎引起混乱。在using System; using CoreAnimation; using CoreGraphics; using YourNameSpace; using YourNameSpace.iOS; using UIKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(GradientView), typeof(GradientViewRenderer))] namespace YourNameSpace.iOS { public class GradientViewRenderer : BoxRenderer { public override void Draw(CGRect rect) { //base.Draw(rect); GradientView formsGradientView = Element as GradientView; var currentContext = UIGraphics.GetCurrentContext(); currentContext.SaveState(); var colorSpace = CGColorSpace.CreateDeviceRGB(); var startColor = formsGradientView.StartColor; var startColorComponents = startColor.ToCGColor().Components; var middleColor = formsGradientView.MiddleColor; var middleColorComponents = middleColor.ToCGColor().Components; var endColor = formsGradientView.EndColor; var endColorComponents = endColor.ToCGColor().Components; nfloat[] colorComponents = { startColorComponents[0], startColorComponents[1], startColorComponents[2], startColorComponents[3], middleColorComponents[0], middleColorComponents[1], middleColorComponents[2], middleColorComponents[3], endColorComponents[0], endColorComponents[1], endColorComponents[2], endColorComponents[3] }; nfloat[] locations = { 0f, 0.5f, 1f }; var gradient = new CGGradient(colorSpace, colorComponents, locations); var startPoint = new CGPoint(0, NativeView.Bounds.Height); var endPoint = new CGPoint(NativeView.Bounds.Width, NativeView.Bounds.Height); currentContext.DrawLinearGradient(gradient, startPoint, endPoint, CGGradientDrawingOptions.None); currentContext.RestoreState(); } } } 中,该参数的类型为push,但是它像引用全局struct stackNode *一样被操纵。但是root纯粹是本地的,对全局root = new没有影响。但是,root 确实会影响全局范围。这破坏了堆栈的逻辑状态,并且您在size++开头的错误处理程序认为pop并没有抱怨。然后,该函数会忠实地取消引用size == 3,从而使程序崩溃。

正确的堆栈类不应使用全局数据。它应该将所有必要的状态封装在结构中。这使其可重用,从而可以创建多个堆栈(这是我在使用的大多数类中想要的属性)。

其他一些建议:

  • 尽可能避免使用side effects。可以进行临时调试,但可以将打印与程序逻辑完全分开。
  • 如果您打算编写错误处理程序,请打印到root并避免使用像stderr这样的不可思议的值,这些值可能会误认为实际的节点数据。
  • Don't cast the result of malloc。这样可以抑制错误,并且视觉上很吵。
  • 硬编码return '\0';感觉很随意。我不确定是否有这个意义(但是如果有的话,将其添加到结构中)。如果每个节点内有关堆栈的元数据太多(理想情况下应该没有),请创建一个capacity结构以包含此元数据,并将其指向实际的Stack链。
  • 另一个堆栈设计要点:stackNode / malloc很慢。对于字符数据,带有free指针的简单数组将更快,更容易实现。您可以通过在top时周期性地将数组加倍并在top >= capacity时收缩来对分配调用进行摊销。

这里有一个快速的重写方法(不建议使用top < capacity / 2包装器结构或数组):

Stack