我正在尝试为两个数组页面和价格赋值。
#include<stdio.h>
int main()
{
static int pages[3];
static int price[3];
int i;
printf("nEnter the no. of pages and price of the book:n");
for (i=0; i<=3; i++)
{
printf("provide input:");
scanf(" %d %d", &pages[i], &price[i]);
}
for (i=0; i<=3; i++)
{
printf(" %d %d", pages[i], price[i]);
}
getch();
return 0;
}
输出如下:
Enter the no. of pages and price of the book:
Provide Input:98
12
Provide Input:87
54
Provide Input:99
34
Provide Input:89
45
45 12 87 54 99 34 89 45
在这里,输入的最后一个元素的值,即 (price[3]=89) 被分配给数组 Pages (pages[0]) 的第一个元素。 为什么会这样?
我了解建议对相关数据使用结构。但是,为什么会有这种奇怪的行为呢?
您的状况i <= 3
. 3
也满足了这一点。因此,将访问pages[3]
和pages[3]
,这在这两种情况下都是未定义的行为。索引从 C 语言中的 0
开始,因此具有 x
元素的数组在 [0; x - 1]
中具有明确定义的索引。
将条件更改为i < 3
以解决问题并呈现程序的明确定义。
你的数组只有 3 个元素的空间,所以你要过一个。将它们放大或更改循环以使用<
而不是<=
:
for (i=0; i < 3; i++)
{
/* Do things with pages[i] and price[i] */
}
通常,当我们声明任何变量或数组时,它们会获得彼此接近或之后的内存。在这种情况下,当您声明价格和页面时,它们会获得前三个元素的内存:
价格。。。。。。。。。。页
12 54 45 | 98 87 99
但是,当您尝试向页面和价格添加另一个元素时:
价格。。。。。。。。。。。。页
12 54 45 | 45 87 99 | 89
在这里,当您尝试输入 price[3] 时,它会获取 page[0] 的内存,因此它用 45 覆盖它,但在页面之后没有声明任何内容,因此 page[3] 从外部获取内存并且不会覆盖任何内容。
尝试运行此代码,您的疑问将消除:
*
#include<stdio.h>
int main()
{
static int pages[3];
static int price[3];
int i;
printf("nEnter the no. of pages and price of the book:n");
for (i=0; i<=3; i++)
{
printf("provide input:");
scanf(" %d %d", &pages[i], &price[i]);
}
for (i=0; i<=3; i++)
{
printf(" %d %d", &pages[i], &price[i]);
}
printf("n");
for (i=0; i<=3; i++)
{
printf(" %d %d", pages[i], price[i]);
}
getch();
return 0;
}
- *
正如其他人所说,超出数组(或一般对象)的范围写作 - 甚至阅读!- 是一个严重的错误。但是你的程序暴露的行为实际上是非常预期的,只要对程序的内存布局有一点了解。
您的数组是具有"自动存储持续时间"的局部变量,vulgo:它们在堆栈上分配。在您的实现中(我认为这是 C 实现的标准),堆栈向较小的地址增长。稍后定义的对象驻留在内存中较低的地址:首先定义pages
,然后定义prices
-- prices
内存中较低。(但是每个数组中的元素都必须按从低地址到高地址排列。原因是对于任何数组arr
,arr[i]
等价于 *(arr+i)
,其中求和确实向arr
的数值地址添加一个值,因此该元素的地址高于正i
的arr
。
由于数组是立即连续定义的,并且出于对齐原因不需要填充,因此它们在内存中直接相邻。
所以:
- 首先定义
pages
并在某个地址"创建"。 -
prices
在此之后定义,并在下一个较小的可用地址创建。
索引 - 超出较低地址处对象的边界进入下一个对象的内存,朝向更高的地址。在堆栈上,这是之前定义的对象:
价格的第一要素, 地址 Y | | 最后一个元素 | 的价格, | 地址 Y+2 | | 五 五堆栈以这种方式增长 <- |---价格 ---|--- 页数 ----|地址以这种方式增长 -> |----|----|----|----|----|----| ^ ^ | | | 的最后一个元素 | 页面、地址 | x+2 | 第一个元素 页数,地址 x(即 y+3!这就是你写的!
从这个草图中可以合理地认为,当你访问prices+3
,即紧靠prices
上方的内存时,你最终访问了pages
的第一个元素,它是在prices
之前声明的,因此在堆栈上占据更高地址的内存。
通过越界索引访问内存是 C 中相当常见的错误,它不会(通常也不能)检查数组边界。这些错误可能是微妙的,不会被注意到,或者至少在很长一段时间内"不被理解"。如果你写到离原始对象更远的内存,你会覆盖存储在堆栈上的记账信息,就像返回地址一样,这通常会使程序崩溃(以一种难以找到崩溃位置的方式,因为该信息已被覆盖)。