-1

I'm currently learning C Programming through Dan Gookin's book Beginning C Programming for Dummies.

One of the topic I'm currently reading is on the fact that arrays are in fact pointers. Dan attempted to prove that with the following code:

#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);
}

My question is really with line 17. I realized that if I do not reintialize the pointer again as in line 17, the peek values of pointer pn being displayed at the second for loop sequence are a bunch of garbage that do not make sense. Therefore, I would like to know why is there a need to reintialize the pointer pn again for the code to work as intended?

alk
  • 69,737
  • 10
  • 105
  • 255
xhxh96
  • 649
  • 1
  • 7
  • 14

7 Answers7

2

Since pn is incremented in the first loop, after the first loop is finished, pn will point to an address beyond the numbers array. Therefore, you must initialize pn to the beginning of the array before the second loop since you use the same pointer for printing the contents.

s7amuser
  • 827
  • 6
  • 18
2

An array is not a pointer, but C allows you to assign the array to a pointer of the type of the variable of the array, with the effect that that pointer will point to the first item in the array. That's what pn = numbers does.

pn is a pointer to an int, not to an array. It points to a single integer. When you increment the pointer, it just shifts to the next memory location. The shift it makes is the size of the type of the pointer, so int in this case.

So what does this prove? Not that an array is a pointer, but only that an array is a continuous block of memory that consists of N times the size of the type of your array item.

When you run the second loop, your pointer arrives at a piece of memory that doesn't belong to the array anymore, and so you get 'garbage' which is just the information which happens to exist at that location.

If you want to iterate over the array again by incrementing a pointer, you will have to reinitialize that pointer to the first item. The for loop does only do one thing, which is counting to 10. It doesn't know about the array and it doesn't know about the pointer, so the loop isn't going to automatically reset the pointer for you.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • 1
    Ah I see. Just to clear things up a little, that's what he's trying to say - that the code is really to prove array is a continuous block of memory with N times the size of memory for the type of array rather than to prove that arrays are pointers. It's just that the chapter is generally on how arrays behave like pointers. Sorry for the confusion caused :( – xhxh96 Jun 21 '16 at 12:24
  • There is no garbage in the standard. It is undefined behaviour, nothing else. – too honest for this site Jun 21 '16 at 12:50
1

Because you have changed the address contained in pn in the statement pn++ in the following code snippet.

for(x=0;x<10;x++)
    {
        *pn=x+1;
        pn++;
    }
asad_hussain
  • 1,959
  • 1
  • 17
  • 27
1

The pn pointer is being used to point into the numbers array.

The first for-loop uses pn to set the values, stepping pn throught the data element by element. After the end of the loop, pn points off the end of numbers (at a non-allocated 11th element).

For the second for-loop to work, i.e. to use pn to loop through numbers again by stepping through the array, pn needs to be moved to the front of the numbers array, otherwise you'll access memory that you shouldn't be looking at (non-allocated memory).

Kusalananda
  • 14,885
  • 3
  • 41
  • 52
1

First arrays are not pointers. They decay to pointers when used in function calls and can be used (almost) the same.

Some subtle differences

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) is here 5 * sizeof(int) whereas sizeof(pa) is the size of a pointer.

Now for your question:

After first loop, pn points to p[10] and no longer to p[0]. That's the reason why you must reset it.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
1

Just to drive the point home, arrays are not pointers. When you declare numbers as int numbers[10], you get the following in memory:

         +---+
numbers: |   | numbers[0] 
         +---+
         |   | numbers[1]
         +---+
          ...
         +---+
         |   | numbers[9]
         +---+

There's no storage set aside for a separate pointer to the first element of numbers. What happens is that when the expression numbers appears anywhere, and it isn't the operand of the sizeof or unary & operators, it is converted ("decays") to an expression of type "pointer to int", and the value of the expression is the address of the first element of the array.

What you're doing with pn is setting it to point to the first element of numbers, and then "walking" through the array:

         +---+ 
numbers: |   | <------+ 
         +---+        |
         |   |        |
         +---+        |
          ...         |
         +---+        |
         |   |        |
         +---+        |
          ...         |
                      |
         +---+        |
     pn: |   | -------+ 
         +---+

The expression pn++ advances pn to point to the next integer object, which in this case is the next element of the array:

         +---+ 
numbers: |   | 
         +---+ 
         |   | <------+
         +---+        |
          ...         |
         +---+        |
         |   |        |
         +---+        |
          ...         |
                      |
         +---+        |
     pn: |   | -------+ 
         +---+

Each pn++ advances the pointer until, at the end of the first loop, you have the following:

         +---+ 
numbers: |   | 
         +---+ 
         |   | 
         +---+ 
          ...  
         +---+ 
         |   | 
         +---+ 
          ...  <------+
                      |
         +---+        |
     pn: |   | -------+ 
         +---+

At this point, pn is pointing to the object immediately following the end of the array. This is why you have to reset pn before the next loop; otherwise you're walking through the memory immediately following numbers, which can contain pretty much anything, including trap representations (i.e., bit patterns that don't correspond to a legal value for the given type).

Trying to access memory more than one past the end of an array invokes undefined behavior, which can mean anything from your code crashing outright to displaying garbage to working as expected.

John Bode
  • 119,563
  • 19
  • 122
  • 198
  • Thanks for the thorough explanation and visual walk through. Really helped in understanding how the code works. – xhxh96 Jun 23 '16 at 07:50
0

During the fill array, the pointer pn is incremented and the data is placed on array. Same pointer variable used to print the array content. Since this reinitialise is done.

Jeyaram
  • 9,158
  • 7
  • 41
  • 63