【问题标题】:Why does passing a struct in this way produce a segfault?为什么以这种方式传递结构会产生段错误?
【发布时间】:2014-02-08 16:53:10
【问题描述】:

我正在尝试掌握 c 的窍门,但我不知道为什么这段代码会产生段错误。

// In src/test.c

#include <stdio.h>

typedef struct {
    int length;
    int *arr[1000];
} Stack;

void push(Stack *stack, int el) {
    (*stack->arr)[stack->length++] = el;
}

int pop(Stack *stack) {
    return (*stack->arr)[--stack->length];
}

int main(int argc, char* argv[]) {
    Stack stack;
    push(&stack, 5);
    printf("%d\n", pop(&stack));
    return 0;
}

然后我编译运行:

$ gcc src/test.c -o test && ./test
[1]    79484 segmentation fault  ./test

【问题讨论】:

  • 好吧,是哪一行导致了错误???
  • 我什至不知道如何找到,但在缩小代码范围后,我相当确定它在 pushpop 函数中。对 c 来说仍然非常新。
  • 你没有初始化stack.length。 (并使用-g 编译并使用gdb 进行调试。)
  • int *arr[1000] 真的是你想要的吗?
  • 另外,您将指针数组与指向数组的指针混淆了,并且您没有为指针分配内存。

标签: c memory segmentation-fault


【解决方案1】:

你有一些问题。

就像其他人提到的那样,您的 int length struct member 永远不会设置为零,因此可以包含任何内容。

您必须将长度设置为 0。

其次,int *arr[1000]integer pointers 的数组。所以简单地将int 分配给特定的数组位置是错误的。

你想要更像这样的东西:

// In src/test.c

#include <stdio.h>

typedef struct {
    int length;
    int arr[1000]; // Code change (create an array of integers)
} Stack;

void push(Stack *stack, int el) {
    stack->arr[stack->length++] = el; // Code change (no need for additional
                                      // structure member dereference).
}

int pop(Stack *stack) {
    return stack->arr[--stack->length]; // Code change (no need for additional
                                        // structure member dereference).
}

int main(int argc, char* argv[]) {
    Stack stack;
    stack.length = 0; // Code change (set the starting length value to 0)
    push(&stack, 5);
    printf("%d\n", pop(&stack));
    return 0;
}

【讨论】:

    【解决方案2】:

    在您的结构中,“长度”从未初始化,因此它包含垃圾。当你然后参考:

    (*stack->arr)[stack->length++]
    

    它正在一个未定义的位置索引内存。因此,您需要一些函数,例如“init_stack()”来将结构数据成员初始化为众所周知的值(例如零)。

    【讨论】:

      【解决方案3】:

      结构体中数组的类型错误;应该是int arr[1000];

      正如所写,您到处都在使用未初始化的变量; lengtharr 中的任何指针都没有设置为任何可靠的值(尽管指针应该是普通的 int)。因为您的堆栈中有指针而不是 int,所以您有一个非常复杂的表达式来访问堆栈((*stack-&gt;arr)[stack-&gt;length++] 等),这应该更简单,如下面的重写代码所示。

      #include <stdio.h>
      
      typedef struct
      {
          int length;
          int arr[1000];
      } Stack;
      
      void push(Stack *stack, int el)
      {
          stack->arr[stack->length++] = el;
      }
      
      int pop(Stack *stack)
      {
          return stack->arr[--stack->length];
      }
      
      int main(void)
      {
          Stack stack = { 0, { 0 } };
          push(&stack, 5);
          printf("%d\n", pop(&stack));
          return 0;
      }
      

      【讨论】:

        【解决方案4】:
        #include <stdio.h>
        
        typedef struct {
            int length;
            int arr[1000];
        } Stack;
        
        void push(Stack *stack, int el) {
            (stack->arr)[stack->length++] = el;
        }
        
        int pop(Stack *stack) {
            return (stack->arr)[--stack->length];
        }
        
        
        int main(int argc, char* argv[]) {
            Stack stack;
            memset(&stack,0,sizeof(Stack));
            push(&stack, 5);
            printf("%d\n", pop(&stack));
            return 0;
        }
        

        拇指规则是在访问之前分配内存。

        【讨论】:

        • (stack-&gt;arr)[stack-&gt;length++] 中的括号并不是真正需要的,尽管它们实际上并没有错。使用 memset() 代替初始化程序可以工作,但编译器可以更好地完成这项工作。
        猜你喜欢
        • 2011-01-27
        • 2013-02-19
        • 2016-02-08
        • 2021-08-11
        • 2020-09-11
        • 1970-01-01
        • 2014-03-21
        相关资源
        最近更新 更多