如何修复从C中的函数传递指针时出现的分段错误?

如何修复从C中的函数传递指针时出现的分段错误?,c,string,pointers,segmentation-fault,C,String,Pointers,Segmentation Fault,GDB告诉我第52行导致了分段故障。我不明白为什么。我正在实现一个简单的堆栈。它有两个功能:弹出和推送。看来pop不起作用了。pop的目的是检索堆栈上最顶层的值。然而,当它试图这样做时,我得到了一个分段错误。有人知道原因吗 /************************************************************************* * stack.c * * Implements a simple stack structure for char*

GDB告诉我第52行导致了分段故障。我不明白为什么。我正在实现一个简单的堆栈。它有两个功能:弹出和推送。看来pop不起作用了。pop的目的是检索堆栈上最顶层的值。然而,当它试图这样做时,我得到了一个分段错误。有人知道原因吗

/*************************************************************************
 * stack.c
 *
 * Implements a simple stack structure for char* s.
 ************************************************************************/

// for strdup() in the testing code
#define _XOPEN_SOURCE 500

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

// the capacity of the stack
#define CAPACITY 10

//global variable used to keep track of pop and push


typedef struct
{
    // storage for the elements in the stack
    char* strings[CAPACITY];

    // the number of elements currently in the stack
    int size;
}stack;

// declare a stack (as a global variable)
stack s;


/**
 * Puts a new element into the stack onto the "top" of the data structure
 * so that it will be retrived prior to the elements already in the stack.
 */
bool push(char* str) 
{
    s.strings[s.size++] = strdup(str);
    return false;
}

/**
 * Retrieves ("pops") the last ("top") element off of the stack, following
 * the "last-in, first-out" (LIFO) ordering of the data structure. Reduces
 * the size of the stack.
 */
char* pop(void)
{
    char *ptr = s.strings[--s.size]; 
    s.strings[s.size] = NULL;

    return ptr;   
}

/**
 * Implements some simple test code for our stack
 */
int main(void)
{
    // initialize the stack
    s.size = 0;

    printf("Pushing %d strings onto the stack...", CAPACITY);
    for (int i = 0; i < CAPACITY; i++)
    {
        char str[12];
        sprintf(str, "%d", i);
        push(strdup(str));
    }
    printf("done!\n");

    printf("Making sure that the stack size is indeed %d...", CAPACITY);
    assert(s.size == CAPACITY);
    printf("good!\n");

    printf("Making sure that push() now returns false...");
    assert(!push("too much!"));
    printf("good!\n");

    printf("Popping everything off of the stack...");
    char* str_array[CAPACITY];
    for (int i = 0; i < CAPACITY; i++)
    {
        str_array[i] = pop();
    }
    printf("done!\n");

    printf("Making sure that pop() returned values in LIFO order...");
    for (int i = 0; i < CAPACITY; i++)
    {
        char str[12];
        sprintf(str, "%d", CAPACITY - i - 1);
        assert(strcmp(str_array[i], str) == 0);
        free(str_array[i]);
    }
    printf("good!\n");

    printf("Making sure that the stack is now empty...");
    assert(s.size == 0);
    printf("good!\n");

    printf("Making sure that pop() now returns NULL...");
    assert(pop() == NULL);
    printf("good!\n");

    printf("\n********\nSuccess!\n********\n");

    return 0;
}
在push-and-pop函数W中,您可以访问s.strings[-s.size]/s.strings[s.size++],而不检查s.size是否在合理的范围内

因此,在将尽可能多的元素推到堆栈顶部之后,行断言!推得太多了!;在分配的数组之外添加一个元素

类似地,在弹出主函数中的每个元素后,堆栈为空且assertpop==NULL;尝试访问堆栈数组的-1元素,这是未定义的行为,也是SEGFULT的另一个可能来源

编辑:顺便说一下,尽管这可能是您所问的错误的来源,但您的代码似乎更容易出错。使用指针算术或数组访问时,请记住始终执行边界检查。

请看这篇文章:

printf("Making sure that push() now returns false...");
assert(!push("too much!"));
printf("good!\n");
在这里,您在堆栈上的字符串太多,堆栈已满。推送函数实际上并没有检查您是否超出了容量,它只是附加了字符串

bool push(char* str) 
{
    s.strings[s.size++] = strdup(str);
    return false;
}
这意味着您将超出堆栈的边界,破坏内存,将堆栈大小设置为11,然后混乱随之发生

推送功能可能会执行以下操作:

bool push(char* str) 
{
   if (s.size >= CAPACITY)
      return false;

    s.strings[s.size++] = strdup(str);
    return true;
}
pop函数需要进行类似的检查,否则最终可能会改变大小 即使堆栈是空的,也会出现以下情况:

char* pop(void)
{
    if (s.size == 0) 
        return NULL;

    char *ptr = s.strings[--s.size]; 
    s.strings[s.size] = NULL;

    return ptr;   
}

哪一个是第52行?char*ptr=s.strings[-s.size];您应该使用了解为什么分段错误的答案。推得太多!:这将写入post数组范围,因为推送函数不验证大小。从那里你的程序将有一个不稳定的行为。