作为我们在编程语言学院培训的一部分,我们还学习了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)
>
我的问题是,是否有可能仅通过笔记本中的编写代码,而不检查任何编译器,就可以确定某个指针(或一般而言所有变量)在内存中的其他变量之前还是之后?
请注意,我并不是说数组变量,所以数组中的所有元素必须按顺序排列。
答案 0 :(得分:8)
在此声明中:
(&ptr2)[3] = str;
ptr2
是在char *ptr2
内用main
定义的。使用此定义,编译器负责为ptr2
提供存储。允许编译器为此使用所需的任何存储空间-可能在ptr1
之前,可能在ptr1
之后,可能很近,也可能很远。
然后&ptr2
使用ptr2
的地址。允许这样做,但是我们不知道该地址相对于ptr1
或其他任何地址,因为允许编译器使用它想要的任何存储。
由于ptr2
是char *
,所以&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");
}
}
,您将看到内存地址及其内容!
今天愉快。