我目前正在通过Dan Gookin的书“Beginning C Programming for Dummies”学习C编程。
我目前正在阅读的一个主题是数组实际上是指针。 Dan试图通过以下代码证明:
#include <stdio.h>
int main()
{
int numbers[10];
int x;
int *pn;
pn = numbers; /* initialize pointer */
/* Fill array */
for(x=0;x<10;x++)
{
*pn=x+1;
pn++;
}
pn = numbers;
/* Display array */
for(x=0;x<10;x++)
{
printf("numbers[%d] = %d, address %p\n",
x+1,*pn,pn);
pn++;
}
return(0);
}
我的问题实际上是第17行。我意识到如果我没有像第17行那样再次重新指向指针,那么在第二个pn
循环序列中显示的指针for
的查看值是一堆没有意义的垃圾。因此,我想知道为什么需要再次重新指针pn
以使代码按预期工作?
答案 0 :(得分:3)
数组不是指针,但C允许您将数组分配给数组变量类型的指针,其效果是该指针将指向数组中的第一项。这是pn = numbers
的作用。
pn
是指向int的指针,而不是指向数组的指针。它指向一个整数。增加指针时,它只会切换到下一个内存位置。它所做的移动是指针类型的大小,因此在这种情况下为int
。
那么这证明了什么?并不是说数组是一个指针,而只是一个数组是一个连续的内存块,它的数量是数组项类型的N倍。
当你运行第二个循环时,你的指针到达了一块不再属于数组的内存,所以你得到了垃圾&#39;这只是该地点恰好存在的信息。
如果要通过递增指针再次遍历数组,则必须将该指针重新初始化为第一个项目。 for循环只执行一项操作,即计数为10.它不知道数组并且它不知道指针,因此循环不会自动重置指针给你。
答案 1 :(得分:2)
由于pn
在第一个循环中递增,因此在第一个循环结束后,pn
将指向numbers
数组之外的地址。因此,您必须在第二个循环之前将pn
初始化为数组的开头,因为您使用相同的指针来打印内容。
答案 2 :(得分:1)
因为您在以下代码段中更改了pn
语句中pn++
中包含的地址。
for(x=0;x<10;x++)
{
*pn=x+1;
pn++;
}
答案 3 :(得分:1)
pn
指针用于指向numbers
数组。
第一个for
- 循环使用pn
设置值,逐个元素地逐步执行pn
。在循环结束后,pn
指向numbers
的末尾(在未分配的第11个元素处)。
要使第二个for
- 循环起作用,即通过单步执行pn
再次循环numbers
,需要将pn
移动到numbers
数组的前面,否则你将访问你不应该看的内存(未分配的内存)。
答案 4 :(得分:1)
第一个数组是不是指针。当它们在函数调用中使用时,它们衰减指针,并且可以(几乎)使用它们。
一些微妙的差异
int a[5]; /* array */
int *pa = a; /* pointer */
pa[0] = 5;
printf("%d\n", a[0]); /* ok it is the same here */
printf("address of array %p - address of pointer %p, value of pointer\n",
&a, &pa, pa); /* &a is the same as pa not &pa */
printf("size of array %d - size of pointer %d\n", sizeof(a), sizeof(pa));
sizeof(a)
在这里5 * sizeof(int)
而sizeof(pa)
是指针的大小。
现在提问:
首次循环后,pn
指向p[10]
,不再指向p[0]
。这就是你必须重置它的原因。
答案 5 :(得分:1)
只是为了让点回家,数组不是指针。当您将numbers
声明为int numbers[10]
时,您会在内存中获得以下内容:
+---+
numbers: | | numbers[0]
+---+
| | numbers[1]
+---+
...
+---+
| | numbers[9]
+---+
没有存储空间用于指向numbers
的第一个元素的单独指针。当表达式numbers
出现在任何地方,并且不是 sizeof
或一元&
运算符的操作数时,它会被转换(“衰减“)到”指向int
的指针“类型的表达式,表达式的值是数组的第一个元素的地址。
您使用pn
做的是将其设置为指向numbers
的第一个元素,然后“遍历”数组:
+---+
numbers: | | <------+
+---+ |
| | |
+---+ |
... |
+---+ |
| | |
+---+ |
... |
|
+---+ |
pn: | | -------+
+---+
表达式pn++
使pn
前进到指向下一个整数对象,在本例中是数组的下一个元素:
+---+
numbers: | |
+---+
| | <------+
+---+ |
... |
+---+ |
| | |
+---+ |
... |
|
+---+ |
pn: | | -------+
+---+
每个pn++
使指针前进,直到第一个循环结束时,您有以下内容:
+---+
numbers: | |
+---+
| |
+---+
...
+---+
| |
+---+
... <------+
|
+---+ |
pn: | | -------+
+---+
此时,pn
指向紧跟在数组末尾之后的对象。这就是你必须在下一个循环之前重置pn
的原因;否则你在numbers
之后立即遍历内存,它可以包含几乎任何东西,包括陷阱表示(即,与给定类型的合法值不对应的位模式)。
尝试访问超过数组末尾的内存超过一个内存会调用未定义的行为,这可能意味着从您的代码直接崩溃到显示垃圾到按预期工作。
答案 6 :(得分:0)
在填充数组期间,指针pn
递增,数据放在数组上。用于打印数组内容的相同指针变量。因为这种重新初始化已经完成。