我正在尝试使用以下 c 代码读取随机内存位置的值
main()
{
int a,*b;
printf("enter the value of a");
scanf("%d",&a);
b=a;
printf("%d\n%d\n",a,*b);
getch();
}
但是,negative values
当通过. 我做错了什么?指针没有负值吗?zero
a
scanf
我正在尝试使用以下 c 代码读取随机内存位置的值
main()
{
int a,*b;
printf("enter the value of a");
scanf("%d",&a);
b=a;
printf("%d\n%d\n",a,*b);
getch();
}
但是,negative values
当通过. 我做错了什么?指针没有负值吗?zero
a
scanf
问题是你可能在一个现代的、全方位服务的操作系统上运行,它提供了一个比大多数 c 编程书籍介绍中描述的更复杂的抽象机器。
特别是,操作系统对访问任意地址施加了限制。当您查看与标准变量关联的地址时,您不会注意到这一点,因为您确实有权使用堆栈和数据段,并且alloc
函数族负责确保您有权访问堆的各个部分他们交给你。
因此,您正在做的是访问您没有权限的内存,这会导致在大多数操作系统上出现称为“分段错误”的故障,并且会突然结束您的程序。
你能为这个做什么?
在堆上分配一个大块,通过调用char *p = malloc(1000000);
然后找到类似的起始和结束地址,printf("start:\t%p\nend\t%p\n",(void*)p,(void*)(p+1000000));
并且只输入该范围内的数字。
请注意,说明%p
符打印说明符以十六进制输出,因此您可能希望以相同的基数输入地址。标准库函数strtol
在这方面会有所帮助。
一种更复杂的方法是使用操作系统的 API 请求对任意地址的访问权限,但对于某些值,操作系统可能会简单地拒绝。
我在这里看到了一些混乱,只是想要一个指针。
首先,您向用户询问一个值。这可以。然后将该值指定为指针的位置b
。这可能很好,但可能不会。
想一想,*(-500) 是什么意思?*(0) 是什么意思?
一般来说,您永远不能在不先检查或操作它的情况下只接受用户输入并使用它。这是安全漏洞的来源之一。
如果您想尝试取消引用内存,请首先对一些值进行硬编码。在调试器中加载程序,看看会发生什么。
int c;
b = 500;
c = *b; // what happens?
b = 0;
c = *b; // what happens?
b = -100;
c = *b; // what happens?
让我为你大大简化...
在几乎所有具有大多数操作系统的现代计算机中,机器中很少有内存可以由您的程序直接寻址。你不能拿一个指针,把它指向某个东西,然后尝试阅读它。它几乎总是会失败。
一般会出现以下三种情况:
在 1980 年代具有完整 64k 内存的旧 8 位计算机中,您可以读取任何您想要的位置,这很好。没有那么多了。
理论上,您有权读取虚拟地址空间内的任何地址(例如,32 位机器上的 0 到 0xFFFFFFFF)。0 和负数不是问题——一旦将它们分配给指针,它们就会被转换为非负值。
在实践中,它是行不通的。操作系统将保护自己(和您)免受此影响 - 它不会让您从不真正属于您的地址中读取。也就是说,如果你没有分配内存页面并且没有在那里写东西,操作系统不会让你从那里读取。
此外,您并不真正拥有整个地址空间 - 它的下半部分归内核等人所有,因此操作系统不会让您访问它。
根据我所听到的,指针完全是积极的。0(NULL 指针)保证不指向任何东西,并且会导致程序停止。此外,操作系统(如果我没记错的话甚至是硬件)提供内存保护。这就是为什么程序过去能够相互崩溃的原因,但现在这种情况已经不太常见了。当您运行程序时,操作系统会决定它可以访问哪些内存,如果您尝试访问不属于您的内存,则会引发段错误。
再说一次,也许你只是想要b = &a
?这将b
指向与a
存在相同的位置,因此,当您*b
将其等同于存储在a
.
如我所见,您将 b 声明为指针,因此执行 a=b 是错误的。你会得到分段错误。指针只显示指针而不是整数、浮点数或字符的值。或者你可以做 b = &a,这意味着 b 显示到 a 的内存地址。因此,您可以打印存储在 a 中的值。