int *ptr = 5; 和 int *ptr = 变量的地址 有什么不同?(涉及IT技术)

3

虽然很基础,可能看起来有些愚蠢,但我想了解以下两种情况的区别:int *ptr = 450xc8750; (一些数字)int *ptr= &a;(变量的地址)

我已经知道的是:

  • 指针用于存储变量的地址并修改所指变量的内容(但我想知道如何实现)
  • 在后一种情况下,我可以将*ptr分配给不同的合法地址。
  • 但是,在第一种情况下,这是不合法的!

为什么后者如果地址/数字都是整数就是不合法的?在内存中存储时会有哪些不同处理方式?

我有两个几乎相同的代码/程序,用于突出显示此问题:

情况1:

#include <stdio.h>

int main()
{    
    int *ptr = 0xc42; // is this stored in read only memory?!! which later leads to seg faults in further assignments?!
    *ptr = 45; //illegal leads seg fault.
    return 0;
}

案例二:

int main()
{
    int a=10, b=20;
    int *ptr = &a;  // is here get any special treatment and object will be created for *ptr!!!
    *ptr = &b; //legal
    printf(" *ptr = %d \n", *ptr);
    *ptr = 20; //legal !!
    printf(" *ptr = %d \n", *ptr);
    *ptr = 50; //legal
    printf(" *ptr = %d \n", *ptr);
    return 0;
}

我们可以看到*ptr = 20*ptr = 50是合法的,没有出现分段错误。为什么int *ptr = 0xc989或5的赋值与int *ptr = &variable不同呢?请注意区分它们的类型和地址。

1
使用 int *ptr = .... 语句,你声明了一个指向整数的指针,并用一个不是真实地址的值进行初始化。这个值会赋给 ptr,而不是 *ptr!之后你访问了这个地址,但这是非法的,因为这个地址本身就是非法的。 - Roberto Caboni
@RobertoCaboni 谢谢回复。那么,在第二种情况下,int * ptr = &a是否创建了对象,以后可以将其更改为不同的整数值呢? 但是在情况1中缺少这一点? 我的理解是正确的吗? 我正在试图了解情况1赋值如何导致非法,请纠正我如果我错了。 - B_San
3个回答

4

让我们从基础开始:指针是一种变量,其中包含指向给定类型数据的地址。如果我们声明

datatype* foo;

foo(目前未初始化)将包含类型为datatype的变量的地址,并对其进行解引用

*foo = ...;

我们正在访问该地址并将其值存储在那里。

在这两种情况下,我们都有* foo,但它们不是同一个东西!

  • 在第一种情况下,星号引用了datatype。变量类型为datatype *;变量名为foofoo 包含一个地址。
  • 在第二种情况下,我们正在取消引用该地址,以便访问它。星号引用变量以执行指针取消引用。

因此,当你写

int *ptr = 0xc42; // is this stored in read only memory?!!
                  // which later leads to seg faults in further assignments?!
*ptr = 45; //illegal leads seg fault.
  • 使用 int *ptr = 0xc42;,你在告诉编译器声明一个名为 ptr 的变量,类型为 int *,并且其初始值为 0xC42注意: 正如用户 Lundin 所说,这个赋值需要进行进一步的类型转换才能成为有效的 C 代码)
  • 使用 *ptr = 45;,你正在访问由 ptr 指向的地址,并将值赋为 45。这是合法的吗?如果先前分配了有效地址,通常情况下是合法的(例如,如果你使用 & 运算符将另一个变量的地址分配给指针,如 int *ptr = &a;)。但是,如果你将一个随机整数赋值给它... 那么很可能会导致分段错误。

3

从逻辑上来说,如果您确定位置0xc989保存了您需要的内容,那么int *ptr = 0xc989是完全有效的(正如Roberto Caboni所说的那样)。

技术上讲,就像Lundin所说的,您需要根据C标准进行强制类型转换。


谢谢您的回复,我基本上想知道,即使我们假设0xc989具有有效内容,那么下一个*ptr = 45的赋值是否合法?如果不是,那么案例1和案例2之间有什么区别呢? - B_San
1
@B_San如果它不是只读的,你可以读/写。 - Soner from The Ottoman Empire
1
@B_san请看我的评论。 - Roberto Caboni
1
它并不完全有效,它不是有效的C语言。 - Lundin
2
@Lundin 是正确的,但不是 OP 错误的真正核心。他们认为使用 int *ptr= 42; 就可以仅针对该连续的 *ptr 解除引用指针。 - Roberto Caboni
@Lundin 感谢分享链接,它为我提供了一些关于整数指针的有效用途的见解。+1 - B_San

3
首先,int *ptr = 0xc42; 不是有效的 C 代码,并且在编译器配置为严格标准 C 的情况下将无法编译通过。使用 gcc、clang 和 icc 编译器需要使用 -std=c11 -pedantic-errors 参数进行编译。详见"Pointer from integer/integer from pointer without a cast" issuesint *ptr = (int*)0xc42; 是有效的 C 代码,但是有些可疑。这会把一个地址存储在指针变量本身中,而不是存储一个值。因此,如果你知道内存地址 0xc42 上有一个 int 大小的项目(例如一个内存映射的硬件寄存器),那么可以直接指向它。但是,在这样做时,最好使用 volatilevolatile int *ptr = (volatile int*)0xc42;。这样的代码主要用于嵌入式系统和其他与硬件相关的编程。
至于为什么第二个例子可以正常工作,是因为这些地址是由链接器分配的,而不是由程序员分配的,所以它们将指向有效的已分配数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接