【问题标题】:Segfault when dereferencing void ** arguments取消引用 void ** 参数时的段错误
【发布时间】:2017-02-08 21:40:31
【问题描述】:

我在这里缺乏对指针的理解。 foo1foo 类型的指针。在 dequeue 中,有一个 foo 类型的项目列表,这些项目是由 queueList 传入的动态分配的。我的任务是让 foo1 指向队列的头部,但是,访问传递给 dequeue()foo1 指针*data 会导致段错误。这是我缺乏理解的地方。 *data 不是指 foo1 指针吗?

struct foo
{
//Properties Here
};

int main()
{
    struct foo* foo1;
    dequeue(myQueueList, (void*) foo1);
}

void dequeue(struct queue* queueList, void **data)
{
    *data = NULL; //Causes Seg fault if I do this too
    *data = queueList->head->data; //Seg fault if I do this as well
    return;
}

我的队列定义为:

struct queue
{
    node * head;
    //other stuff
};

struct node
{
    void * data;
    //other stuff
};

编辑: foo1 未在 main 中初始化。我想通过将其设置为等于已入队的不同 struct foo* 指针来在出队中对其进行初始化。

Edit2: queue 包含一个 struct foo* 指针列表。

Edit3:感谢 wildplasser,它使用 (void*)foo1 -> (void*)&foo1 修复。但是为什么我必须使用 &foo1 而不是 (void*)?

【问题讨论】:

  • dequeue(myQueueList, (void*) foo1); -->> dequeue(myQueueList, &foo1); 另外:你的 *foo1 指针不指向任何地方;没有它指向的 foo 对象,并且它不是 NULL。
  • @wildplasser 为什么当 foo1 在出队中初始化时 foo1 需要 NULL?我想要的是 foo1 指向堆中的另一个 foo 类型。还是我想错了?我想要相当于: struct foo* foo1 = queueList->head->data;其中 data 是 void* 类型。
  • queueList->head->data 一个struct foo* 类型伪装成void*
  • 在这种情况下不需要它。但是当非 NULL 时,出队例程可以做不同的事情(例如解除分配,或根本不分配)。未初始化的数据(通常)只是一个坏习惯。 Ald 将指针 作为返回值返回 根本不需要任何指向指针的指针。
  • data 是一个未初始化的指针,所以你不能取消引用它。呵呵。

标签: c pointers void-pointers


【解决方案1】:

在这段代码中:

struct foo* foo1;
dequeue(myQueueList, (void*) foo1);

表达式(void *)foo1 导致未定义的行为,因为您使用了未初始化指针的值。

你想要做的概念是将foo1地址传递给函数,这样函数就可以修改foo1。您需要& 运算符来查找事物的地址。

但是该函数对struct foo * 一无所知。 void ** 不是通用指针类型;它是一个指向 void * 的指针,仅此而已。所以要让这段代码在不改变dequeue的定义的情况下工作,你需要创建一个void *变量:

void *vfoo;
dequeue(myQueueList, &vfoo);
struct foo *foo1 = vfoo;

如果你能改变它的设计,使用dequeue 会更容易;特别是,让它返回void *。然后你可以写struct foo *foo1 = dequeue(myQueueList);

注意:在 cmets 中建议使用 dequeue(myQueueList, (void **)&vfoo);,但是由于严格的别名违规,这将导致未定义的行为。 struct foo * 类型的对象无法通过 void * 类型的左值访问。

【讨论】:

  • 我明白了,所以我只想澄清一下。如果 foo1 是 void 类型,则为 arg2 传入 (void*) foo1 等效于传递 *foo1?当我通过POINTER&foo1' I am passing the ADDRESS` 时,可以通过在我的dequeue 函数中使用*data 将其取消引用为指针。而对于struct foo *foo1 = vfoo;,如果我们这样做,为什么我们不键入 cast vfoo 到 (struct foo*)vfoo?我同意如果我们更改设计,使用 dequeue 会更容易,但我的教授向我提供了一个头文件,我们不允许为此作业更改。
  • foo1 转换为(void*)(void**) 会导致什么样的未定义行为?以及 dequeue() 在传递给 arg2 时如何看到 (void **)&foo1(void*) &foo1 中的 foo1?
  • @TommySaechao 回复。第二条评论,我在回答中解释了这一点。使用未初始化指针的值会导致未定义的行为。转换一个指针使用它的值。 (void *)&foo1(void **)&foo1 作为函数参数具有相同的效果,因为函数原型确保前者转换为后者
  • 回复。第一条评论,(void *)foo1 不等于 *foo1foo1 是一个变量。 (void *)foo1 表示将变量的值转换为void **foo1 表示foo1 指向的对象。 &foo1foo1的地址,是一个指针。你可以写(struct foo *)vfoo,但最好避免多余的演员表。
猜你喜欢
  • 2020-03-20
  • 2014-01-05
  • 2015-01-04
  • 2014-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多