Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.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 - Fatal编程技术网

C 指针与数组的混淆

C 指针与数组的混淆,c,C,我们有 我想知道下面两段代码是怎么做的 int a[5]={10, 20, 30, 40, 50}; 如果我们有 int *ptr = (int *)(&a+1); int *t = (int *)(&a -1); 结果应该是什么?让我们一件一件地看一看 &a表示a的地址。因此,它得到整数10的地址。 &a+1是从该点开始的下一个指针。所以它是存储在内存中变量a之后的东西。坏主意。 &a-1是在a之前存储在内存中的东西。又是一个坏主意 *(a+1)是由a加上一个整数指向

我们有

我想知道下面两段代码是怎么做的

 int a[5]={10, 20, 30, 40, 50};
如果我们有

 int *ptr = (int *)(&a+1);
 int *t = (int *)(&a -1);

结果应该是什么?

让我们一件一件地看一看

&a
表示a的地址。因此,它得到整数10的地址。
&a+1
是从该点开始的下一个指针。所以它是存储在内存中变量
a
之后的东西。坏主意。
&a-1
是在
a
之前存储在内存中的东西。又是一个坏主意

*(a+1)
是由a加上一个整数指向的位置处的东西。那将是
a[1]
或20。
*(ptr-1)
a
,因为
ptr
&a+1
,所以
ptr-1
&a
。它是
a
的指针值。将其打印为
%d
是一个错误。如果你说
**(ptr-1)
,你会从
printf
中得到一个更有意义的
10

*(t+1)
也是
a
,如上所述,但加号和减号是切换的。

所有问题都来自
&a
的使用,它是指向“五个整数的数组”的指针,因此指针算法(当您考虑地址时)会按
大小(a)
(例如,如果
int
是4个字节,并且编译器不需要为对齐目的而进行填充,则可能是20个字节——这是合理的假设,当然远不能确定

那么,在

 printf("%d  %d  %d \n", *(a+1), *(ptr-1), *(t+1));
ptr
是指向内存地址“sizeof(a)大于地址a”处int的指针,
t
类似地指向“sizeof(a)小于地址a”处int的指针。因此…:

int *ptr = (int *)(&a+1);
int *t = (int *)(&a -1);

结果应该是什么

很可能是分段冲突,否则
20
后跟两个完全任意的整数值。由于
ptr
t
是指向
int
的指针,因此它们的
-1
+1
的地址算术缩放不会对
&a
进行补偿(内存地址的缩放是通过
sizeof(int)
,而不是
sizeof(a)
!),因此
ptr-1
t+1
指向(所谓的;-)
int
分别是
a
结束后的一些
int
a
开始前的一些
int

无法知道在这些任意地址上是否存在允许进程寻址的内存(因此可能存在分段冲突),如果存在任何可访问内存,则其“视为
int
”的内容可能是什么

Edit:@caf指出,
ptr-1
不是无效的——它正确地指向
a
的最后一个元素;因此输出(除非存在分段错误,@NullUserException认为不太可能,但在这一点上我们不同意;-)将以第三个“任意”之前的
2050
开始垃圾。点是,根据C标准,可以有效地计算(尽管不使用)数组的指针“仅过一个端点,并且数组的大小必须正好是该数组的长度乘以其元素的大小(如果需要,可以对元素的类型进行填充,如果需要,可以在元素自身的大小中显示,但不能对整个数组进行填充)。微妙但重要;-)。

“结果应该是什么?”

下次您想知道像这样的小代码段应该做什么时,请查看以下内容:

我得到的结果是:

2050134520820

编辑:

当您运行一个程序时,看到这样的输出,您会发现自己在问:“那个值是从哪里来的?”您可能遇到了未定义的行为


在这种情况下,第三个值并不指向您可能认为它会指向的位置。它读取未初始化的内存(很可能)、进程空间中的代码所拥有的内存,但在您的程序(加载的库或C运行时)之外的内存,或者与此程序无关的内存(不太可能,因为内存受保护)。

因为
a
的类型是array-of-5-
int
s,这意味着
&a
的类型是指向-array-of-5-
int
s的指针

当你从一个指针上加上或减去1时,你要求它指向内存中该类型的下一个或上一个对象。因此
&a+1
正在创建一个指向内存中
a
之后的数组-5-
int
的指针(该数组不存在),并且
&a-1
正在创建一个指针,指向内存中
a
之前的数组-5-
int
(该数组也不存在)。在内存中,它看起来是这样的(其中每个单元格代表一个
int
):

当在表达式
*(a+1)
中使用
a
时,它被转换为指向其第一个元素的指针,因此指向
int
的指针指向
10
值。向其中添加一个,然后使指向下一个
int
-
a+1
的指针指向
20
值。
*(a+1)
然后获取该值,因此打印的第一个数字是20

由于
ptr
也是指向-
int
的指针,这意味着
ptr-1
ptr
之前创建一个指向int的指针,在这种情况下,它将指向50。因此打印的第二个数字是50

类似地,
t+1
t
之后立即创建一个指向
int
的指针-在这种情况下,它是上图中的第二个
。这是一个未初始化的值-它可能打印任何内容,甚至导致程序崩溃

Address:    &a-1                      &a                      &a+1
Contents:  | ?  | ?  | ?  | ?  | ?  | 10 | 20 | 30 | 40 | 50 | ?  | ?  | ?  | ?  | ?  |

当您尝试时,您的程序说了什么?这是一个测试问题,并不是假设在计算机上运行就能回答的
Address:    &a-1                      &a                      &a+1
Contents:  | ?  | ?  | ?  | ?  | ?  | 10 | 20 | 30 | 40 | 50 | ?  | ?  | ?  | ?  | ?  |
Address:    &a-1                      &a                       &a+1
            t    t+1                  a   a+1            ptr-1 ptr
Contents:  | ?  | ?  | ?  | ?  | ?  | 10 | 20 | 30 | 40 | 50  | ?  | ?  | ?  | ?  | ?  |