当我编写以下代码时,我正在学习C中的指针:
#include <stdio.h>
main()
{
char *p = 0;
*p = 'a';
printf("value in pointer p is %c\n", *p);
}
编译代码时,编译成功。虽然,当我执行其out
文件时,发生了一个小时错误:Segmentation Fault (core dumped)
我无法理解为什么会发生运行时错误。毕竟,指针p
指向字符a
,因此输出应该是a
。
虽然,当我编写以下代码时,它已成功编译并运行:
#include <stdio.h>
main ()
{
char *p = 0;
char output = 'a';
p = &output;
printf("value which pointer p points is %c\n", *p);
}
有人可以解释为什么第一个程序失败,而第二个程序成功运行?
答案 0 :(得分:11)
您的代码会调用未定义的行为,因为您要取消引用NULL
1 指针。指针需要指向有效的内存,这是实现你想要的一个简单的方法
#include <stdio.h>
int // `main()' MUST return `int'
main(void)
{
char *pointer;
char value;
pointer = &value; // Now the pointer points to valid memory
*pointer = 'a';
printf("value in pointer p is %c\n", *pointer);
return 0;
}
1 6.3.2.3指针
- 值为0的整型常量表达式,或者类型为
醇>void *
的表达式,称为空指针常量。 66)如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较。66) 宏
NULL
在 (和其他标题)中定义为空指针常量;见7.19。6.5.3.2地址和间接运营商
<强>语义强>
- 一元
醇>*
运算符表示间接。如果操作数指向函数,则结果是函数指示符;如果它指向一个对象,则结果是指定该对象的左值。如果操作数的类型为''指向类型'',则结果的类型为''type''。如果为指针指定了无效值,则unary *运算符的行为未定义。 102)102) 因此,
&*E
相当于E
(即使E
是空指针),&(E1[E2])
到((E1)+(E2))
。如果E是函数指示符或左值是一元&
运算符的有效操作数,则总是如此,*&E
是函数指示符或左值等于E
。如果*P
是左值而T是对象指针类型的名称,则*(T)P
是左值,其类型与T
点的类型兼容子>由一元
*
运算符取消引用指针的无效值中有一个空指针,一个地址与指向的对象类型不对齐,以及一个对象的地址结束后它的一生。
答案 1 :(得分:1)
在第一个示例中,您将p
设置为0,这在大多数实现中与NULL
相同。然后尝试取消引用该指针(读/写p
指向的内存位置),这将导致核心转储。 p
不指向字符a
。这个*p = 'a'
表示“获取p
指向的内存位置并将a
放在那里”。
在第二个示例中,您将p
设置为output
的地址,因此它指向已知的内存位置。然后,当您取消引用时,您正在读取p
点所在位置的值,即output
。这是有效的用法。
答案 2 :(得分:1)
指针是&#34;特殊&#34;存储另一个变量地址的变量。看看这个程序,我希望它能帮助你弄清楚指针是什么以及如何使用它:
#include <stdio.h>
int main(void){
int x = 10, *pointer = 0;
pointer = &x;
printf("\nThe address of x : %p.\n", &x);
printf("\nThe address of the pointer : %p.\n", pointer);
printf("\nThe value of x : %d.\n", x);
*pointer += 10;
printf("\nThe value of x after we modifed it with the pointer : %d.\n\n", x);
return 0;
}
如果你编译并给这个程序一个运行,这将是它的输出:
x的地址:0xbf912108。
指针的地址:0xbf912108。
x的值:10。
我们用指针修改它后的x的值:20。
您可以清楚地看到指针的地址与变量本身相同。这就是为什么当你修改指针时(例如在我的程序中我做*pointer += 10
)它实际上修改了变量。