有人能解释一下C如何在for循环中处理结构声明吗?(见示例)

有人能解释一下C如何在for循环中处理结构声明吗?(见示例),c,pointers,C,Pointers,我不太直接使用C语言,一个基本语言的细微差别会让我倒退,我想更好地理解它,这样我以后就可以避免它了 我正在使用以下链接中找到的队列实现 这是一个非常常见的队列,其中值被推送和弹出。(FIFO)但由于某种原因,我推送到队列上的最后一个值将队列中的所有值设置为相同的值 我从以下代码开始 Queue q; queue_init(&q); for (int i=0;i<10;i++) { MyData *in_md; in_md->mNumber = i;

我不太直接使用C语言,一个基本语言的细微差别会让我倒退,我想更好地理解它,这样我以后就可以避免它了

我正在使用以下链接中找到的队列实现

这是一个非常常见的队列,其中值被推送和弹出。(FIFO)但由于某种原因,我推送到队列上的最后一个值将队列中的所有值设置为相同的值

我从以下代码开始

Queue q;
queue_init(&q);
for (int i=0;i<10;i++) {
    MyData *in_md;
    in_md->mNumber = i;
    queue_push(&q, in_md);

    MyData *h = (MyData *)q.head->data;
    MyData *t = (MyData *)q.tail->data;

    NSLog(@"in_md: %i", in_md->mNumber);
    NSLog(@"h->mNumber: %i", h->mNumber);
    NSLog(@"t->mNumber: %i", t->mNumber);
    if (q.head->link) {
        MyData *l = (MyData *)q.head->link->data;
        NSLog(@"l->mNumber: %i", l->mNumber);
    }
}
队列q;
队列初始化(&q);
对于(int i=0;imNumber=i;
队列推送(&q,在md中);
MyData*h=(MyData*)q.head->data;
MyData*t=(MyData*)q.tail->data;
NSLog(@“在\u md:%i中”,在\u md->mNumber中);
NSLog(@“h->mNumber:%i”,h->mNumber);
NSLog(@“t->mNumber:%i”,t->mNumber);
if(q.head->link){
MyData*l=(MyData*)q.head->link->data;
NSLog(@“l->mNumber:%i”,l->mNumber);
}
}
但我发现,当我弹出值时,每个实例的数值都是9。我认为我有一些指针错误,并尝试了一段时间来修复它。我认为,由于我在for循环块的内部声明了,它将是一个具有唯一内存地址的唯一实例。最终将代码更新为以下内容

Queue q;
queue_init(&q);
for (int i=0;i<10;i++) {
    void *data = malloc(sizeof(MyData)); // key change
    MyData *in_md = (MyData *)data;
    in_md->mNumber = i;
    queue_push(&q, data);

    MyData *h = (MyData *)q.head->data;
    MyData *t = (MyData *)q.tail->data;

    NSLog(@"in_md: %i", in_md->mNumber);
    NSLog(@"h->mNumber: %i", h->mNumber);
    NSLog(@"t->mNumber: %i", t->mNumber);
    if (q.head->link) {
        MyData *l = (MyData *)q.head->link->data;
        NSLog(@"l->mNumber: %i", l->mNumber);
    }
}
队列q;
队列初始化(&q);
对于(int i=0;imNumber=i;
队列推送(&q,数据);
MyData*h=(MyData*)q.head->data;
MyData*t=(MyData*)q.tail->data;
NSLog(@“在\u md:%i中”,在\u md->mNumber中);
NSLog(@“h->mNumber:%i”,h->mNumber);
NSLog(@“t->mNumber:%i”,t->mNumber);
if(q.head->link){
MyData*l=(MyData*)q.head->link->data;
NSLog(@“l->mNumber:%i”,l->mNumber);
}
}
现在,确保创建了一个新实例,因为使用了malloc,我将它转换为一个变量,我可以设置int值。这将创建一个输出,正如我所期望的那样

我假设C应该是这样工作的,但我没有预料到。通常在Java、C#甚至JavaScript等其他语言中,在块中声明变量会创建一个新的变量实例,这正是我在这里所期望的。但事实并非如此

这种情况下会发生什么?

在您的代码中:

您创建了一个指针:

MyData *in_md;
在不为指针保留内存的情况下(这是malloc在第二个代码块中所做的),您将值分配给它的成员:

in_md->mNumber = i;
您基本上是在访问未定义的内存。在您的情况下,该值为“9”,但也可能导致应用程序崩溃

在第二个代码块中,您为该指针分配了内存,然后将其存储在队列中—这是正确的方法


请记住,在最终释放队列之前,需要使用free()方法释放内存。

声明指针会创建指针,但不会创建指针对象。您仍然需要初始化指针(就像需要初始化任何其他变量一样),但对于指针,它需要初始化为内存地址,这可以通过使用new(C++)或malloc(C)来分配内存(也可以通过&)分配现有变量的内存地址)

将声明与初始化相结合通常是一种良好的编程实践。请确保从不使用:

Type identifier;
并始终使用:

Type identifier = initializing_expression;

将确保您不会遇到此类问题,并将为您省去不少麻烦。请注意,这与其他语言没有太大区别(在Java中,该语言完全禁止使用未初始化的变量,而在JavaScript中,未初始化的声明将导致其值为未定义).

您的第二个实现确实是一条路要走

我想你会被挂断的部分是,在_md;中执行“MyData*确实会在某种意义上创建一个“新实例”,但它不会创建MyData的新实例,而是创建一个MyData指针的新实例。指针在实际指向某个有用的对象之前,对你没有多大帮助,因此需要调用malloc

因此,在Java中,您将在\u md=new MyData()中拥有
MyData,它将自动为MyData分配空间,但在C中,您拥有
MyData*in\u md=(MyData*)malloc(sizeof(MyData))
b因为您对内存的控制级别要低得多。在这之后,您可以像在Java或C中一样处理对象。唯一需要记住的是,在Java中,如果内存分配失败,可能会抛出一个很好的错误,但在C中不是这样,因此最好确保in md为n最后,C缺少垃圾收集,因此确保在退出队列后释放()已malloc'的项非常重要

Queue q;
queue_init(&q);
for (int i=0;i<10;i++) {
    MyData *in_md = (MyData *)malloc(sizeof(MyData));
    in_md->mNumber = i;
    queue_push(&q, (void*)in_md);

    MyData *h = (MyData *)q.head->data;
    MyData *t = (MyData *)q.tail->data;

    NSLog(@"in_md: %i", in_md->mNumber);
    NSLog(@"h->mNumber: %i", h->mNumber);
    NSLog(@"t->mNumber: %i", t->mNumber);
    if (q.head->link) {
        MyData *l = (MyData *)q.head->link->data;
        NSLog(@"l->mNumber: %i", l->mNumber);
    }
}
队列q;
队列初始化(&q);
对于(int i=0;imNumber=i;
队列_-push(&q,(void*)在_-md中);
MyData*h=(MyData*)q.head->data;
MyData*t=(MyData*)q.tail->data;
NSLog(@“在\u md:%i中”,在\u md->mNumber中);
NSLog(@“h->mNumber:%i”,h->mNumber);
NSLog(@“t->mNumber:%i”,t->mNumber);
if(q.head->link){
MyData*l=(MyData*)q.head->link->data;
NSLog(@“l->mNumber:%i”,l->mNumber);
}
}

malloc之后,我嗅到了一个美味的内存泄漏,也没有空检查。你的帖子是不正确的。它断言“变量声明”在Java和JavaScript中的工作原理是相同的——它们不一样。但是,Java和C支持非常相似的词法范围(请注意,对象生命周期的处理方式不同)。(在JavaScript中,只有一个新的函数作用域可以引入新的变量。)@WTP:Good catch!我需要得到这个:@hari,如果它有“分段错误”写在背面的我会买它。你还需要检查malloc是否返回NULL,如果返回NULL,就不要再使用指针了。检查malloc是否返回NULL其实并不是那么必要……如果你已经达到了这个程度,你的程序可能会崩溃。(一个r如何处理