指针地址位置

时间:2019-02-21 14:59:11

标签: c arrays pointers memory-management

作为我们在编程语言学院培训的一部分,我们还学习了C。在测试期间,我们遇到了以下问题:程序输出将是什么:

#include <stdio.h>
#include <string.h>

int main(){
    char str[] = "hmmmm..";
    const char * const ptr1[] = {"to be","or not to be","that is the question"};
    char *ptr2 = "that is the qusetion";

    (&ptr2)[3] = str;

    strcpy(str,"(Hamlet)");
    for (int i = 0; i < sizeof(ptr1)/sizeof(*ptr1); ++i){
        printf("%s ", ptr1[i]);
    }
    printf("\n");
    return 0;
}

稍后,在检查了答案之后,很明显,单元格(&ptr2)[3]与&ptr1 [2]中的存储单元相同,因此程序的输出为:to be or not to be (Hamlet)

我的问题是,是否有可能仅通过笔记本中的编写代码,而不检查任何编译器,就可以确定某个指针(或一般而言所有变量)在内存中的其他变量之前还是之后?

请注意,我并不是说数组变量,所以数组中的所有元素必须按顺序排列。

4 个答案:

答案 0 :(得分:8)

在此声明中:

(&ptr2)[3] = str;

ptr2是在char *ptr2内用main定义的。使用此定义,编译器负责为ptr2提供存储。允许编译器为此使用所需的任何存储空间-可能在ptr1之前,可能在ptr1之后,可能很近,也可能很远。

然后&ptr2使用ptr2的地址。允许这样做,但是我们不知道该地址相对于ptr1或其他任何地址,因为允许编译器使用它想要的任何存储。

由于ptr2char *,所以&ptr2是指向char *的指针,也称为char **

然后(&ptr2)[3]尝试引用char *处的&ptr2数组的元素3。但是C的计算模型中没有数组。那里只有一个char *。当您尝试在没有数组元素3的情况下引用数组元素3时,行为不是由C标准定义的。

因此,此代码是一个错误的示例。看来测试作者误解了C,并且此代码未说明预期的目的。

答案 1 :(得分:2)

不,这是不可能的,无法做出这样的假设。

通过在变量的空间外书写,此代码将调用未定义的行为,基本上是“非法”的,运行它时可能发生任何事情。 C语言规范没有说明可以按一定的特定顺序在栈上分配变量,但是可以说访问随机内存是未定义的行为。

基本上,此代码非常可怕,绝不应该使用,即使在教学环境中也是如此。这让我很难过,人们如何误解了C并仍然将其教给他人。 :/

答案 2 :(得分:2)

char *ptr2 = some initializer;

(&ptr2)[3] = str;

当评估&ptr2时,您将获得指向该初始值设定项的指针的存储地址。

当您执行(&ptr2)[3]=something时,尝试将3*sizeof(void*)的位置写在距离字符串地址ptr2较远的位置。这是无效的,几乎可以确定它以分段错误结束。

答案 3 :(得分:-1)

通常使用以下结构将程序加载到内存中: 堆栈,Mmap文件,堆,BSS(未初始化的静态变量),数据段(已初始化的静态变量)和Text(已编译的代码)

您可以在此处了解更多信息: https://manybutfinite.com/post/anatomy-of-a-program-in-memory/

根据您声明变量的方式,它将转到前面所述的位置之一。

编译器将按他希望的时间安排BSS和Data段变量,因此通常没有机会。都不是堆变量(操作系统将获得更适合分配的内存的内存块)

在堆栈(这是一种LIFO结构)中,变量相互重叠,所以如果您有:

int a = 5;
int b = 10;

您可以说a和b将一个接一个地放置。因此,在这种情况下,您可以知道。

还有一个例外,即如果变量是结构或数组,则它们总是像我之前所说的那样放置,每个变量都放在最后一个变量之后。

在您的代码中ptr1是一个由chars组成的数组,因此它将遵循我所说的异常。

实际上,请执行以下练习:

#include <stdio.h>
#include <string.h>

int main(){
    const char * const ptr1[] = {"to be","or not to be","that is the question"};
    for (int i = 0; i < 3; i++) {
            for (int j = 0; j < strlen(ptr1[i]); j++) 
            printf("%p -> %c\n", &ptr1[i][j], ptr1[i][j]);
        printf("\n");
    }

}

,您将看到内存地址及其内容!

今天愉快。