显式分配C指针的地址

时间:2011-10-10 23:26:15

标签: c memory pointers

$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=0x7fffffffe2bc;
    y=0x7fffffffe3bc;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

在运行时产生分段错误(没有编译时警告/错误) 编辑 :(警告:谢谢@KeithThompson)

  

x.c:在函数'main'中:
  x.c:6:警告:赋值使用整数而不使用强制转换

[ 8626.812415] x[3198]: segfault at 7fffffffe2bc ip 000000000040054c sp 00007fff66a1dd70 error 6 in x[400000+1000]

但是当我将x,y分配给q时,w为此

$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=&q;
    y=&w;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

获取输出0。我甚至从gdb检查了q和w的地址,我得到0x7fffffffe2bc的q

为什么我不能强制指针指向特定位置并为其提供要存储的值?

修改 地址0x7fffffffe2bc不是未分配。 这是来自gdb的q的地址

Breakpoint 1, main () at x.c:10
10      *x=3;*y=4;
(gdb) p q
$1 = 0
(gdb) p &q
$2 = (int *) 0x7fffffffe2bc
(gdb) 

我理解这种编写代码的方式很糟糕,如果不是错误的话。我只是写了这个,看看地址的明确分配是否有效。我永远不会浪费时间明确地分配地址。做这样的事情实际上听起来非常迟钝:)

$ gdb -q ./a.out 
Reading symbols from /home/eknath/needed2/a.out...done.
(gdb) r
Starting program: /home/eknath/needed2/a.out 
0

Program exited normally.
(gdb) q

5 个答案:

答案 0 :(得分:3)

因为您没有为数据分配内存,只需指针。你最好捣乱内存,最坏的情况是打一个未分配的内存段。无法知道要使用的地址 - 每次运行应用程序时,它们都可能不同。

如果要动态分配变量(即在您自己的控制下),请使用malloc:

int *x = (int*) malloc( sizeof(int) );
*x = 2;

// when done, free the memory
free( (void*) x );

答案 1 :(得分:1)

此代码:

int *x,q;
...
x=0x7fffffffe2bc;

无效。这是一种约束违规,这意味着需要任何符合标准的编译器来发出诊断消息。您说“编译此程序时没有警告/错误”,这意味着您使用的是旧编译器,或者您正在使用新的编译器。

x的类型为int*; 0x7fffffffe2bc是某种整数类型。没有从整数类型到int*的隐式转换(除了0的特殊情况,空指针常量)。

可以合法地写下这样的内容:

x = (int*)0x7fffffffe2bc;

但这是一个非常糟糕的主意。它使您的程序非常不可移植。它可能(或可能不)恰好在您的特定系统上工作。

无论你想要完成什么,这都不是实现目标的方法。你无法知道0x7fffffffe2bc(当转换为int*时)是一个有效的地址 - 即使它是一个有效的地址,它也不会是你在一个偶数运行程序时环境略有不同。

修改

我尝试通过打印qw的地址然后将地址硬连接到代码中来尝试在我的系统上复制程序(地址完全不同)。每次执行程序时实际地址都会更改,即使我不更改或重新编译程序本身也是如此。我认为有些系统会故意这样做,作为安全功能。 (我看到dmckee的回答已经提到了这一点。)

打印变量的地址,或者使用gdb查看变量,只会告诉您该变量在该特定程序执行中的地址。一旦程序运行完毕,该信息无用,即使您重新运行相同的程序而没有任何更改。

如果您想要q的地址,那么获取该地址的方式为&q

答案 2 :(得分:0)

这种事情完全取决于实现/环境(并且通常是未定义的行为),但它确实在嵌入式系统和其他环境中占有一席之地,在这些环境中,您与绝对一切之间没有操作系统层。< / p>

许多完整服务操作系统随机化堆栈和/或堆的起始地址,以便使攻击更加困难,如果是这种情况,您将无法执行任何可靠的技巧。

答案 3 :(得分:0)

问题既不在代码中,也不在编译器/链接器中。这两个程序都像你期望的那样工作。只有一个很大的: 仅仅因为你可以指向内存并不意味着你将被MMU 允许访问(假设是操作系统)。

让我澄清一下: 通常你只能访问你“拥有”的内存(堆栈/堆)。在这两种情况下,对x和y的赋值都是有效的。棘手的部分是当你访问内存(读或写)时。在第一种情况下,您为指针指定了一些随机值,因此该位置不太可能在程序的范围内(==无法触及此位置)。虽然,在第二种情况下,您正在访问可能拥有的变量的内存位置。

为什么会这样?因为对变量进行优化,q和w将被优化掉,因为它们从未被使用过。

请记住:从不引用未初始化的变量,除非您喜欢问题

答案 4 :(得分:0)

void myFunction(char *addr)
{
#ifdef UMEM_DEBUG
    if (addr == (char *) 0xdeadbeefdeadbeef)
    {
        return;
    }
#endif
...
}

这是有效的,并且是您想要这样做的一个很好的例子。只需根据addr的类型获得正确的类型转换