初始化迭代器指针:分段错误

时间:2014-08-28 16:26:45

标签: c pointers gcc memory

我试图在C中创建队列(作为一个类项目)。他们提供的演示代码是Borland Turbo C.我试图通过gcc重建程序。虽然代码在Turbo C中运行完美,但在gcc运行时期间Segmentation Fault (core dumped)会抛出错误struct node { int data; struct node *link; }; struct queue { struct node *front; struct node *rear; }; void initQ(struct queue *q) { q->front = q->rear = NULL; // Error : Segmentation Fault! (core dumped) } void main() { struct queue *Q; initQ(Q); }

我没有包含不必要的代码部分。逐行试验并测试它。

Segmentation Fault

我确信问题与编译器中的C版本有关。由于Turbo C非常古老,它不支持最新修复。我在代码的其他各个部分出现类似的void displayQ(struct queue *q) { struct node *temp; temp->link = q->front; // Error : Segmentation Fault! (core dumped) } 错误,如:

{{1}}

问题1:为什么gcc会出现这样的运行时错误? (在此代码中)

问题2:为什么代码在Turbo C中运行良好而不是gcc?

问题3:是否有替代这种编程风格的方法?

4 个答案:

答案 0 :(得分:4)

您需要预留空间(使用malloc):

struct queue *Q = malloc(sizeof(*Q));
initQ(Q);

或更好calloc

struct queue *Q = calloc(1, sizeof(*Q));
/* initQ(Q); you don't need this, calloc set all members to NULL */

不要忘记最后致电free(Q);

答案 1 :(得分:3)

void initQ(struct queue *q) {
    q->front = q->rear = NULL;
}

在您的代码q中,当您使用它并指向某个随机地址时,它不会被初始化。尝试:

struct queue Q;
initQ(&Q);

答案 2 :(得分:2)

Q尚未初始化为特定的任何位置,这意味着它是无效的指针值。当您将其传递给initQ时,您会尝试使用->运算符取消引用它。尝试取消引用无效指针会导致未定义的行为,这可能意味着从代码按预期工作到崩溃到损坏数据。

无论Turbo C下有什么初始值,不确定值Q,它都位于可访问的内存区域(尽管如此,它仍然是无效的指针),所以你不会得到你在gcc中所做的段错误。

当您致电initQ时,q 必须指向有效对象。你可以打电话给initQ 现有的队列实例,如下所示:

struct queue Q; // Q is an instance of struct queue, not a pointer to it
initQ( &Q );

或者,您可以创建一个为新的动态分配内存的伪构造函数 队列对象并在其上调用initQ

struct queue *create_queue_element( )
{
  struct queue *q = malloc( sizeof *q );
  if ( q )
    initQ( q );
  return q;
}
...
struct queue *Q = create_queue_element();

答案 3 :(得分:1)

  

问题1:为什么gcc会出现这样的运行时错误? (在此代码中)

因为代码不正确 - 您取消引用初始化指针。


  

问题2:为什么代码在Turbo C中运行良好而不是gcc?

它不能正常工作,它根本不检测错误。 16位DOS代码没有内存保护和虚拟内存的好处。它无法区分属于您的进程的实际内存(在DOS中没有进程内存,因为它不是多任务处理。整个DOS子系统在其自己的受保护VM中运行。您可能拥有的唯一保护是取消引用NULL指针。指针的值将解析为某些非确定性内存位置,并且可能看起来正常工作,直到其他东西使用相同的内存位置用于某些其他目的 - 可能永远不会发生,有时可能发生,或者可能在执行时发生在另一台机器上 - 你无法分辨。

大多数情况下,当您的应用程序变大并使用越来越多的内存时,问题将在代码编写后很久就会出现。如果引用的位置恰好位于您的代码空间中,那么您将有可能在执行时随机更改代码。这些错误很难找到,因为时间因素和代码接近度通常将因果关系分开。

你写的是:

struct queue *Q = NULL ;

您可能遇到过运行时错误报告。这不会使代码更正确,但它确实使得更有可能检测到这样的错误。


  

问题3:是否有替代这种编程风格的方法?

这不是风格问题,而是正确性问题。但是,如果您始终将声明上的指针初始化为指向有效实例或NULL,则可以避免该问题,或者至少可以及早发现错误。

即使在这种情况下,在32位代码中,错误是在运行时检测到的,这无法保证 - 您的初始化指针驻留在堆栈上,在其他情况下可能包含您的进程中有效地址的值,你只是在踩你自己的数据。