3

So I just started learning about pointer arithmetic and I was fiddling around with some of its capabilities. Once I started trying to fool around with pointer arithmetic and classes, I came to a problem. I wrote the following code below:

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;


class Cat
{
public:
    Cat();
    ~Cat();
    int GetAge() { return itsAge; }
    void SetAge(int age) { itsAge = age; }

private:
    int itsAge;

};

Cat::Cat()
{
}

Cat::~Cat()
{
}

int _tmain(int argc, _TCHAR* argv[])
{

    Cat *Family = new Cat[5];
    Family = Family + 1;
    Family->SetAge(3);
    cout << Family[1].GetAge()<< endl;

    return 0;
}

In my mind, I'm creating a pointer called Family which will point to an array of Cat objects. This pointer will represent the address of Family[0]. Then, on the next line, I have pointer Family point to a new address by adding 1 to the pointer itself (so the compiler should take this as moving up an address slot to the next element in the array, Family[1]). Then I set the age to 3 and try and output the value of Family[1]'s age, however the answer I get is -842150451 and not 3. What am I missing?

Himanshu
  • 4,327
  • 16
  • 31
  • 39
Jason
  • 2,198
  • 3
  • 23
  • 59
  • 2
    You have allocated an array of 5 `Cat`s - let's call them `cat[0]` through `cat[4]`. Originally, `Family` points to `cat[0]`. After `Family = Family + 1`, `Family` points to `cat[1]` - which means that `Family[1]` refers to `cat[2]`. So you call `SetAge` on `cat[1]`, but `GetAge` on `cat[2]`. – Igor Tandetnik Jul 24 '15 at 04:31
  • 1
    Also you should deallocate your cat array using `delete[]` operator. – Ari0nhh Jul 24 '15 at 04:33
  • By doing `Family = Family + 1`, the reference to `Family[0]` is lost, and `Family[0]` is now what used to be `Family[1]`, because the index is reset. `Family[1]` is now what used to be `Family[2]`. You are setting the age to what used to be `Family[1]`, but is now `Family[0]`. `cout << Family[0].GetAge()` would work as expected. Bear in mind arrays start at index 0. – Havenard Jul 24 '15 at 04:50
  • -842150451 = 0xCDCDCDCD. You've read a memory region allocated via malloc or new but never written by the application http://stackoverflow.com/q/370195/995714 – phuclv Jul 24 '15 at 05:11

5 Answers5

6

itsAge is not initialised as you haven't set it in the default constructor. It is currently garbage.

Cat::Cat()
: itsAge(0)
{
}

This becomes a problem as Family[1] points to the Cat after the one you initialised. Pointer[1] is the equivalent of *(Pointer + 1).

mat_geek
  • 2,481
  • 3
  • 24
  • 29
  • Okay, I get the gist from you and everyone else who posted here. I'm still a little hazy though on how exactly pointers work with classes on the free store. So your saying that even when I do: Family = Family +1; I am not changing Family[0] to Family[1]. I'm only effecting Cat[0], changing it to Cat[1]? – Jason Jul 24 '15 at 05:11
  • Assume that Family[0] is at memory location 0x1000 and that a cat is 4 octets in length. When you say Family = Family + 1 you are saying Family = 0x1000 + sizeof(*Family) which is Family = 0x1000 + sizeof(Cat) which is Family = 0x1000 + 4 so Family becomes 0x1004. Now Family just points to the second Cat. – mat_geek Nov 09 '15 at 00:54
  • However the main problem is that in C++ there is no default initializer for int and other builtin types. You must specify a value. Many OS/CPU 'helpfully' zero a memory page on allocation, so you wont see the error the first time. Usually just during a demo to the boss/customer. – mat_geek Nov 09 '15 at 01:00
4

I see couple of issues:

  1. itsAge is not initialized in the constructor of the class. Change it to:

    Cat::Cat() : itsAge(0)
    {
    }
    
  2. Your understanding of pointer arithmetic is slightly flawed.

    You have:

    Cat *Family = new Cat[5];   // Family points to the first Cat
    Family = Family + 1;        // Now Family points to the second Cat
    Family->SetAge(3);          // Set the age of the second Cat
    
    cout << Family[1].GetAge()<< endl; // Since Family points to the
                                       // second object, Family[0] is the
                                       // second object. Family[1] is the third
                                       // object, not the second object.
                                       // That is the misunderstanding
    
R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

Please note that when you increment the Family,

Family = Family + 1;

Family points to a location corresponding to Cat[1]. Now you set age of the Cat[1] using:

Family->SetAge(3);

But in next statement you get the value from Family[1] which points to Cat[2] actually:

cout << Family[1].GetAge()<< endl;

Thus, it prints the garbage as Family[1] is equivalent to *(Family+1) i.e. incrementing it again.

Instead you can use Family->GetAge():

Cat *Family = new Cat[5];   
Family = Family + 1; 
Family->SetAge(3);
cout << Family->GetAge()<< endl;

Also keep habit of using delete for the dynamic allocations to prevent memory-leaks.

TryinHard
  • 4,078
  • 3
  • 28
  • 54
1

Try:

Cat *Family = new Cat[5];
(Family + 1)->SetAge(3);
cout << Family[1].GetAge()<< endl;
bhzag
  • 2,932
  • 7
  • 23
  • 39
1

Please see the comments in code below :

#include <iostream>
#include <string>
using namespace std;

class Cat
{
public:
    Cat();
    ~Cat();
    int GetAge() { return itsAge; }
    void SetAge(int age) { itsAge = age; }

private:
    int itsAge;
};

Cat::Cat() : itsAge(0)
{
}

Cat::~Cat()
{
}

int main(int argc, char* argv[])
{

    Cat *cats = new Cat[5];
    for( int i = 0; i < 5; ++i )
    {
      cats[i].SetAge( i + 1 );
    }

    //Here cats points to the first cat so, it will print 2
    cout << cats[1].GetAge()<< endl;

    //Now cat will be pointing to second cat as pointer will be moved forward by one
    cats = cats + 1;

    //below statement will print 3, as cats[0] is pointing to 2nd cat, and cats[1] will be pointing to 3rd cat
    cout << cats[1].GetAge()<< endl;

    return 0;
}
CreativeMind
  • 897
  • 6
  • 19