取消引用指针而不将它们指向变量

时间:2013-06-25 10:14:19

标签: c pointers

我无法理解一些指针是如何工作的。我一直认为,当你创建一个指针变量(p)时,除非要为它设置malloc空间(p = malloc(x)),否则你不能使用deference和assign(* p = value),或者将它设置为另一个变量的地址(p =& a)

但是在此代码中,第一个赋值一致,而最后一个赋值为segfault:

typedef struct
{
    int value;
} test_struct;

int main(void)
{
    //This works
    int* colin;
    *colin = 5;

    //This never works
    test_struct* carter;
    carter->value = 5;
}

当colin没有指向任何备用内存时,为什么第一个工作正常?为什么第二个永远不会工作?

我是用C语言编写的,但具有C ++知识的人也应该能够回答这个问题。

编辑:好的,我知道第一个也不应该工作,但为什么呢。这就是我追求的目标。

4 个答案:

答案 0 :(得分:7)

// This works
int* colin;
*colin = 5;

欢迎使用未定义的行为:它不会崩溃并不意味着它可以正常工作。访问未初始化的指针总是错误的,但有时它不会崩溃。

  除非你为它设置malloc空间或将其设置为另一个变量的地址,否则

无法顺从和分配

这是对的。通常,您需要将指针指向已分配给程序的某个位置。有多种方法可以做到这一点,但它们都归结为您描述的两种情况之一 - 指针指向动态分配的内存(即malloc),或指向静态分配的内存(即变量)。

答案 1 :(得分:2)

  

我一直认为,当你创建一个指针变量(p)时,除非要为它设置malloc空间(p = malloc(x)),否则你不能使用deference和assign(* p = value)它到另一个变量的地址(* p =& a)

出于实际目的,你认为是正确的。最好保持思考。

如果你在你的例子中做了什么,程序的行为是不确定的。什么意味着什么都可能发生,包括误导“工作”的感觉。但它只不过是灾难的秘诀。

答案 2 :(得分:1)

  

我一直认为,当你创建一个指针变量(p)时,除非要为它设置malloc空间(p = malloc(x)),否则你不能使用deference和assign(* p = value)它到另一个变量的地址(* p =& a)

C中有些东西是不允许的,所以C编译器会发出错误并拒绝编译程序,还有其他东西,C标准没有定义任何行为,所以对什么没有限制一个实现可能会...这样做的原因是为实现提供了很大的自由度,并允许它们生成非常快的代码。这与更现代的语言不同,后者更重视保护程序员免受自身错误的影响。因此,程序员编写有效代码的负担会更大。

您的代码是行为未定义的示例。当您取消引用并分配它时,编译器不会生成检查以查看p的值是否有效...它可能包含垃圾,而存储可能位于内存中的任意位置,或者它可能指向无法访问内存和存储将崩溃(由于行为未定义,还有其他可能性,但这些是在常见的实际实现中会出现的)。您的代码在一个商店崩溃而另一个商店崩溃是纯粹的偶然事件,实现细节的工件......不同的编译器,编译器的不同版本,对您的源的轻微更改......其中任何一个事物和其他人可以通过改变恰好在p中的值来改变结果...堆栈上剩下一些任意值,因为p是一个堆栈变量(C语言标准不强制执行)甚至提到堆栈,但常见的实际实现在堆栈上分配auto个变量。)

最重要的是,正如你所知,你的程序是错误的,即使它是“允许的”。正如R. Martinho Fernandes在评论中所说,你是运气不好第一家商店“工作”......在商业产品中,有类似“工作”的东西会非常不幸,因为它可以在任何时候都失败,包括最糟糕的情况。 C语言对你没有帮助......你需要非常自律。

答案 3 :(得分:0)

不要像“我也是”!回答,但其他答案没有回答你的核心问题:

  

好吧,我知道第一个也不应该工作,但为什么呢。这就是我追求的目标。

在这种情况下,您正在调用未定义的行为。 C和C ++标准都很清楚,当变量未初始化时,其内容未定义。当它说未定义时,它意味着,未知。这些指针可以包含字面上的任何内容。因为它们未初始化,它们包含编译器为这两个变量选择的位置所发生的任何内存。

在这种情况下,您的第一个变量发生以包含指向程序内存空间的指针。第二个只是发生以包含指向程序内存空间之外的指针。它可以是从空指针到指向main函数的指针的任何内容。不管它是什么,它是无关紧要的:你不需要知道或关心,因为它是垃圾。无论如何,你都应该把它写在

这是C程序员中常见的表达方式,调用未定义的行为会导致恶魔从你的鼻子飞出来。这是因为C标准非常清楚地表明,当没有定义行为时,编译器可以自由地执行它想做的任何。这包括发射核导弹,将你的银行账户重置为零,或者是,导致有翼的生物从你的鼻腔中飞出来。