2016-06-21 153 views
0

我目前正在通过Dan Gookin的书“Beginning C Programming for Dummies”学习C编程。重新初始化C语言指针

我目前正在阅读的主题之一是事实上,数组实际上是指针。丹试图证明用下面的代码:

#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行再次reintialize指针,以显示指针pn的偷看值第二个for循环序列是一堆没有意义的垃圾。因此,我想知道为什么需要重新调整指针pn以使代码按预期工作?

+10

“*数组实际上是指针*”不,它们不是。 – alk

+4

摆脱那本书... – LPs

+0

*“为什么需要重塑......”*,因为您希望您的程序能够提供您期望的结果。 – StoryTeller

回答

3

数组不是指针,但是C允许将阵列分配给数组的变量的类型的指针,与该指针将指向第一项阵列中的效果。这就是pn = numbers所做的。

pn是一个指向int的指针,而不是数组。它指向一个整数。当你增加指针时,它只是转移到下一个存储位置。它所做的移位是指针类型的大小,所以在这种情况下为int

那么这证明了什么?不是一个数组是一个指针,而只是一个数组是一个连续的内存块,它由数组项的类型的N倍组成。

当你运行第二个循环时,你的指针到达了一块不再属于这个数组的内存,所以你得到'垃圾',这就是恰好存在于那个位置的信息。

如果您想通过递增指针再次遍历数组,您必须重新初始化指向第一项的指针。 for循环只做一件事,它计数到10.它不知道数组,它不知道指针,所以循环不会自动为你重置指针。

+1

啊我明白了。只是为了清楚一点,这就是他想说的 - 这个代码真的要证明,数组是一个连续的内存块,其内存的大小是数组类型的N倍,而不是证明数组是指针。本章只是介绍数组如何像指针一样工作。对不起,因为造成了混淆:( – TruthOrDare

+0

标准中没有垃圾,它是未定义的行为,没有其他的东西 – Olaf

0

在填充数组期间,指针pn递增,数据放置在数组上。用于打印数组内容的同一个指针变量。由于此重新初始化完成。

2

由于pn在第一个循环中递增,所以在第一个循环结束后,pn将指向numbers数组之外的地址。因此,您必须在第二个循环之前将pn初始化为数组的开头,因为您使用相同的指针来打印内容。

1

因为您在以下代码段中更改了pn中的语句pn++中包含的地址。

for(x=0;x<10;x++) 
    { 
     *pn=x+1; 
     pn++; 
    } 
1

pn指针正用于指向numbers数组。

第一个for -loop使用pn来设置值,步骤pn遍历数据元素一个元素。循环结束后,pn指向numbers(在未分配的第11个元素处)结束。

对于第二for -loop工作,即通过数组步进再次使用pn遍历numberspn需要移动到numbers阵列的前面,否则你会访问内存,你不该不在看(未分配的内存)。

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)是一个指针的大小。

现在对于你的问题:

第一循环之后,pnp[10]并不再p[0]。这就是你为什么要重置它必须

+0

感谢指教和数组之间的差异( – TruthOrDare

1

只是为了推动点回家,阵列指针。当你声明numbersint 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,它可以包含相当多的东西,包括陷阱表示(即不符合合法值给定类型,即比特模式)。

尝试访问内存大于一个过去的数组的末尾调用未定义行为,这可能意味着从你的代码直接轰然显示垃圾按预期工作的事情。

+0

感谢您的详细解释和视觉漫步。了解代码的工作原理。 – TruthOrDare