Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C语言中指针的地址存储在哪里?_C_Variables_Pointers_Memory_Memory Address - Fatal编程技术网

C语言中指针的地址存储在哪里?

C语言中指针的地址存储在哪里?,c,variables,pointers,memory,memory-address,C,Variables,Pointers,Memory,Memory Address,我正在学习C语言,目前正在学习指针。我理解将字节地址作为变量存储在内存中的原理,这使得从内存中获取字节并写入内存地址成为可能 但是,我不明白指针的地址存储在哪里。假设指针的值(内存中字节的地址)存储在内存中的某个位置—程序如何知道指针存储在哪里?难道这不需要一个指针换一个指针,从而导致无休止的指针换一个指针换一个指针 更新 实际问题是:“编译器如何将内存地址分配给变量”。我发现了这一点 感谢所有回答的人。指针只是一个变量。这与长变量之间的唯一区别在于,我们知道指针变量中存储的是内存地址,而不是

我正在学习C语言,目前正在学习指针。我理解将字节地址作为变量存储在内存中的原理,这使得从内存中获取字节并写入内存地址成为可能

但是,我不明白指针的地址存储在哪里。假设指针的值(内存中字节的地址)存储在内存中的某个位置—程序如何知道指针存储在哪里?难道这不需要一个指针换一个指针,从而导致无休止的指针换一个指针换一个指针


更新

实际问题是:“编译器如何将内存地址分配给变量”。我发现了这一点


感谢所有回答的人。

指针只是一个变量。这与长变量之间的唯一区别在于,我们知道指针变量中存储的是内存地址,而不是整数

因此,您可以通过与查找任何其他变量地址相同的方式查找指针变量的地址。如果您将这个地址存储在其他变量中,那么这个变量当然也会有一个地址


您的困惑似乎源于指针(即变量地址)可以依次存储这一事实。但它不必存储在任何地方(您仅在出于某种原因需要此地址时才这样做)。从程序的角度来看,任何变量或多或少都是一个命名的内存位置。所以“指向变量的指针”是一个命名的内存位置,它包含了应该“指向”另一个内存位置的值,因此被命名为“指针”。

这是一个实现细节,但是

并非所有地址都存储在内存中。处理器还具有寄存器,可用于存储地址。与存储在内存中的数十亿字节相比,只有少数寄存器可以这样使用,可能是16或32

寄存器中的变量 一些变量将存储在寄存器中。例如,如果需要快速累加一些数字,编译器可能会使用,例如,
%eax
(x86上的寄存器)来累加结果。如果启用了优化,变量只存在于寄存器中是很常见的。当然,在任何给定的时间,只有少数变量可以在寄存器中,所以大多数变量都需要在某个时刻写入内存

如果由于没有足够的寄存器而将变量保存到内存中,则称为“溢出”。编译器非常努力地避免寄存器溢出

int func()
{
    int x = 3;
    return x;
    // x will probably just be stored in %eax, instead of memory
}
堆栈上的变量 通常,一个寄存器指向一个称为“堆栈”的特殊区域。因此,函数使用的指针可以存储在堆栈上,该指针的地址可以通过对堆栈指针执行指针算术来计算。堆栈指针没有地址,因为它是寄存器,并且寄存器没有地址

void func()
{
    int x = 3; // address could be "stack pointer + 8" or something like that
}
编译器选择堆栈的布局,给每个函数一个足够大的“堆栈框架”,以容纳该函数的所有变量。如果禁用优化,变量通常会在堆栈框架中各自获得自己的插槽。启用优化后,插槽将被重用、共享或全部优化

固定地址的变量 另一种选择是将数据存储在固定位置,例如“地址100”

这其实并不罕见。请记住,“地址100”并不对应于RAM,它实际上是一个虚拟地址,指的是程序虚拟地址空间的一部分。虚拟内存允许多个程序都使用“地址100”,并且该地址将对应于每个正在运行的程序中的不同物理内存块

绝对地址也可以在没有虚拟内存的系统上使用,或者用于不使用虚拟内存的程序:引导加载程序、操作系统内核和嵌入式系统的软件可能使用没有虚拟内存的固定地址

绝对地址由编译器通过在机器代码中放入一个称为重定位的“洞”来指定

然后链接器为
x
选择地址,并将地址放入
get\u x()
的机器代码中

与程序计数器相关的变量 另一种选择是将数据存储在相对于正在执行的代码的位置

// global variable... could be stored at address 100
int x = 3;

int get_x()
{
    // this instruction might appear at address 75
    return x; // returns the contents of this address + 25
}
共享库几乎总是使用这种技术,它允许在程序地址空间中的任何可用地址加载共享库。与程序不同,共享库不能选择它们的地址,因为另一个共享库可能会选择相同的地址。程序也可以使用这种技术,这被称为“位置独立的可执行文件”。程序将独立于缺少虚拟内存的系统,或者在具有虚拟内存的系统上提供额外的安全性,因为这使得编写shell代码变得更加困难

就像绝对地址一样,编译器会在机器代码中打一个“洞”,并要求链接器填充它

int get_x()
{
    return x; // return the contents of here + ???
              // Relocation: put the relative address of x here
}

作为指针的变量仍然是变量,其行为与任何其他变量类似。编译器知道变量的位置以及如何访问它的值。只是这个值恰好是一个内存地址,仅此而已

假设指针的值(内存中字节的地址)存储在内存中的某个位置

您分配的字节地址,如下所示

char ch = 'a';
&ch;             // address of ch not stored anywhere
char *p = &ch;   // now the address of ch is stored in p
编译器在符号表中以右偏移量引用。在运行时,编译器生成的指令将使用此偏移量将其从主内存移动到寄存器,以便对其执行某些操作

指针,在您询问的意义上,不会存储在任何地方,它只是引用变量地址时的一种类型,除非您显式创建指针
char ch = 'a';
&ch;             // address of ch not stored anywhere
char *p = &ch;   // now the address of ch is stored in p