为什么设置解除引用指针的值会引发分段错误11? 为了明确我的意思,请查看以下代码:
#include int *ptr; *ptr = 2; int main(){ printf("%dn", *ptr); return 0; }
我认为* ptr = 2会将指针ptr指向的rvalue设置为2.是不是这样? 对于那些c专家程序员,我很抱歉,这真的很容易/很明显。
如果该值具有内存地址,我们是否只允许将取消引用的指针(即* ptr)设置为值? 即喜欢做:
int k = 7; int *ptr = k;
然后:
*ptr = 2;
这里的问题是ptr
没有指向分配的空间。 请参阅以下内容:
#include #include int main(void){ // Create a pointer to an integer. // This pointer will point to some random (likely unallocated) memory address. // Trying set the value at this memory address will almost certainly cause a segfault. int *ptr; // Create a new integer on the heap, and assign its address to ptr. // Don't forget to call free() on it later! ptr = malloc(sizeof(*ptr)); // Alternatively, we could create a new integer on the stack, and have // ptr point to this. int value; ptr = &value; // Set the value of our new integer to 2. *ptr = 2; // Print out the value at our now properly set integer. printf("%dn", *ptr); return 0; }
它不是“非法的”,只是简单的实现定义。 实际上,在某些平台(例如DOS)上,需要特定的内存地址,例如将文本写入以0xB8000开头的video缓冲区,或者将内存映射到SNES上的控制器I / O.
在大多数当前的操作系统中,出于安全原因使用了一个名为ASLR的function,这使得专用地址的古老模式成为过去,有利于通过驱动程序和内核层,这使得它对大多数地方来说是“非法的”你会运行它。
这里最基本的问题是你没有将ptr
分配给有效的内存地址,在某些情况下, 0
是有效的内存地址,但通常不是。 由于ptr
在第一种情况下是全局变量 ,因此它将初始化为0
。 雷米巴尔问了一个很好的后续问题, 最好的回答让我意识到这是一个重新宣布:
*ptr = 2;
然后你将ptr
设置为值为2
,除非偶然指向有效的内存地址。
如果ptr
是一个本地或自动变量,那么它将是未初始化的,它的值将是不确定的。 在C和C ++中使用具有不确定值的指针是未定义的行为 。 虽然允许实现定义行为,但在大多数情况下使用NULL
指针也是未定义的行为。
在大多数试图访问内存的现代系统中,您的进程不拥有将导致分段错误 。
您可以通过几种方式为ptr
分配有效的内存地址,例如:
int k = 7; int *ptr = &k; ^
注意使用of来获取k
的地址,或者你可以使用malloc为它动态分配内存。
您的代码无效,但某些C编译器可能允许它与旧版本的语言兼容。
如果语句出现在函数体外,则语句(包括赋值语句)是非法的(语法错误)。
你有:
int *ptr; *ptr = 2;
在文件范围。 第一行是一个名为ptr
的int*
对象的有效声明,隐式初始化为空指针值。 第二行看起来像赋值语句,但由于它在函数外部,编译器很可能甚至不会尝试以这种方式解释它。 gcc将其视为声明 。 旧版本的C允许您在声明中省略类型名称; C99删除了“隐含int
”规则。 所以gcc对待
*ptr = 2;
相当于
int *ptr = 2;
并产生以下警告:
cc:4:1: warning: data definition has no type or storage class [enabled by default] cc:4:8: warning: initialization makes pointer from integer without a cast [enabled by default]
第一个警告是因为您从声明中省略了int
(或其他类型名称)。 第二个是因为2
是int
类型的值,并且您正在使用它来初始化int*
类型的对象; 没有从int
到int*
隐式转换(除了空指针常量的特殊情况)。
一旦你越过它,你有两个相同对象的声明 – 但它们是兼容的,所以这是允许的。 并且指针变量被初始化为(int*)2
,这是一个垃圾指针值(在内存地址0x00000002
可能没有任何用处)。
在您的main
function中,您可以:
printf("%dn", *ptr);
它试图在该内存地址处打印int
对象的值。 由于该地址不太可能是您的程序有权访问的地址,因此分段错误并不是一个令人惊讶的结果。 (更一般地说,行为未定义。)
(这在C中是一个相当普遍的问题:程序中的小错误可能会导致某些内容仍然编译,但与您的意图完全不同。我想到的方式是C的语法相对“密集”;小随机调整到有效的程序通常会生成不同但语法上有效的程序,而不是创建语法错误。)
这就是你的程序实际上做的事情; 我确定这不是你打算做的。
深呼吸,继续阅读。
这里的东西可能更接近你的意图:
#include int *ptr; int main(void) { *ptr = 2; printf("%dn", *ptr); return 0; }
由于现在没有ptr
的初始化器,因此它被隐式初始化为空指针值。 (如果在main
中定义了ptr
,它的初始值将是垃圾。)赋值语句尝试取消引用该空指针,导致分段错误(同样,行为未定义;分段错误可能是结果)。 执行永远不会到达printf
调用。
我认为
*ptr=2
会将指针ptr
指向的rvalue设置为2.是不是这样?
不完全的。 指针不指向右值; “rvalue”仅仅是表达式的价值。 指针指向对象 (如果它们指向任何东西)。 分配
*ptr = 2;
将值2
赋给ptr
指向的对象 – 但是ptr
不指向对象!
现在让我们看一下你的程序实际可行的版本:
#include int *ptr; int variable; int main(void) { ptr = &variable; *ptr = 2; printf("*ptr = %dn", *ptr); printf("variable = %dn", variable); return 0; }
现在ptr
指向一个对象, *ptr = 2
为该对象赋值。 输出是:
*ptr = 2 variable = 2
以上就是c/c++开发分享为什么将derefernce指针设置为等于原始非法?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/549494.html