我正在尝试将值分配给两个数组Pages和Price。
#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])的第一个元素。为什么会这样?
据我所知,建议对相关数据使用struct。但是,为什么这种奇怪的行为呢?
答案 0 :(得分:3)
您的情况是i <= 3
。 3
也符合这一要求。因此,将访问pages[3]
和pages[3]
,这在两种情况下都是未定义的行为。索引从C中的0
开始,因此具有x
元素的数组在[0; x - 1]
中具有明确定义的索引。
将条件更改为i < 3
以解决问题并使程序定义明确。
答案 1 :(得分:1)
你的阵列只有3个元素的空间,所以你要经过一个结束。
将它们放大或更改循环以使用<
而不是<=
:
for (i=0; i < 3; i++)
{
/* Do things with pages[i] and price[i] */
}
答案 2 :(得分:1)
通常,当我们声明任何变量或数组时,它们会使内存彼此接近或相继接近。在这种情况下,当您声明价格和页面时,它们会在前三个元素之后获得内存:
价格..........页
12 54 45 | 98 87 99
但是当你尝试将另一个元素添加到页面和价格时:
价格............页
12 54 45 | 45 87 99 | 89
这里当你试图输入价格[3]时,它获取了页面[0]的内存,所以它用45覆盖它,但是后面的页面没有声明,所以页面[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;
}
答案 3 :(得分:0)
正如其他人所说,写作 - 甚至是阅读! - 超出数组(或一般对象)的界限是一个严重的错误。但是,程序暴露的行为实际上是非常期待的,并且对程序的内存布局有一点了解。
您的数组是局部变量,具有&#34;自动存储持续时间&#34;,vulgo:它们在堆栈上分配。在您的实现中(我认为这是C实现的标准),堆栈朝着更小的地址发展。稍后定义的对象驻留在较低地址的内存中:首先定义pages
,然后prices
- prices
在内存中较低。 (但每个数组中的 元素都必须从低地址到高地址排列。原因是对于任何数组arr
,arr[i]
等同于{ {1}},其中总和确实为*(arr+i)
的数字地址添加了一个值,因此该元素的地址高于arr
的正arr
地址。)
由于您的阵列已经立即连续定义,并且由于对齐原因不需要填充,因此它们在内存中直接相邻。
所以:
i
,然后创建&#34;&#34;在某个地址。pages
在此之后定义,并在下一个较小的可用地址创建。first element of prices, address y | | last element | of prices, | address y+2 | | V V stack grows this way <- |--- prices ---|--- pages ----| addresses grow this way -> |----|----|----|----|----|----| ^ ^ | | | last element of | pages, address | x+2 | first element of pages, address x (i.e. y+3! This is what you write to!)
从这个草图中可以看出,当您访问prices
时,即prices+3
上方的内存时,您最终会访问prices
的第一个元素,该元素在pages
之前被声明{1}}因此占用堆栈上更高地址的内存。
通过越界索引访问内存是C中相当常见的错误,它不会 - 通常也不能 - 检查数组边界。这些错误可能是微妙的,而且不会引起注意,或者至少是“不被理解的”#34;需很长时间。如果你甚至远离原始对象写入内存,你会通过像返回地址这样的实现覆盖存储在堆栈中的簿记信息,这通常会导致程序崩溃(这种方式很难找到崩溃位置,因为该信息已被覆盖)。