Hello I noticed this weird issue when using multiple pointer structures at the same time.
Can somebody explain to me what is causing it ?
#include <iostream>
using namespace std;
typedef struct A{
int x;
}a;
int main()
{
a *a1, *a2;
a1->x = 3;
cout << a1->x << endl; // display "3"
a2->x = 2;
cout << a2->x << endl; // ...does not display "2" ???
return 0;
}
Before assigning the values to your pointers, the pointers have to be initialized properly.
a *a1, *a2;
These pointers are not initialized. They point to some random location in memory.
The "new" keyword allocates memory for your structure.
You can use it like this:
a *a1 = new A, *a2 = new A;
Related
When initializing a pointer to allocate memory in the heap, should we specify the type as a pointer? That is, should it be:
int* ptr = new num;
OR
ptr = new num;
Both seem to work, and I was under the impression that the first method is better, but doing it is causing some issues in my code below.
I have a class with two member variables, both of which should be pointers to a new int on the heap. When the copy constructor is invoked, it should allocate new memory in the heap, but copy the values of the ints to which the pointers of the argument being passed in are pointing.
#include <iostream>
using namespace std;
// Header file
#pragma once
class numPair {
public:
int *pa,*pb;
numPair(int, int);
numPair(const numPair &);
};
// Implementation file
#include "Cube.h"
#include <iostream>
using namespace std;
numPair::numPair(int a, int b) {
cout << "Constructor invoked!" << endl;
int* pa = new int(a);
cout << "pa = " << pa << endl;
cout << "*pa = " << *pa << endl;
int* pb = new int(b);
cout << "pb = " << pb << endl;
cout << "*pb = " << *pb << endl;
}
numPair::numPair(const numPair& other) {
cout << "Copy invoked!" << endl;
int* ptr = other.pa;
cout << "ptr in copy: " << ptr << endl;
}
// main.cpp file
#include "Cube.h"
#include <iostream>
using namespace std;
int main() {
numPair p(15,16);
cout << "p.pa = " << p.pa << endl;
numPair q(p);
numPair *hp = new numPair(23, 42);
delete hp;
return 0;
}
The output of the main.cpp file is:
Constructor invoked!
pa = 0x5594991a7280
*pa = 15
pb = 0x5594991a72a0
*pb = 16
p.pa = 0x3
Copy invoked!
ptr in copy: 0x3
Constructor invoked!
pa = 0x5594991a72e0
*pa = 23
pb = 0x5594991a7300
*pb = 42
As can be seen, when the constructor is invoked, the pa and pb are both valid memory addresses to ints holding the values 15 and 16. However, once the constructor has finished executing, if I try to access the value of p.pa, it returns 0x3, instead of the memory address from before. This is, of course, a problem on its own and also leads to issues with the copy constructor.
I've found two ways of fixing this.
The first is to change the definition of the constructor by removing the type of pa and pb. That is changing int* pa = new int(a); to pa = new int(b). Repeat the same for pb. Now, p.pa returns the correct memory address.
The second is by commenting out the initialisation and deletion of hp. That is, removing these lines from the main() function:
numPair *hp = new numPair(23, 42);
delete hp;
I don't really understand why specifying the type of a pointer is causing these errors or, in fact, why the memory addresses for p.pa and p.pb are having errors because of the initialization of another instance of the class, especially when considering the fact that hp is initialized after p.
The short answer is that you are misunderstanding the distinction between locally scoped variables and class members. One way to think about this is that you only need to tell your program the type of an identifier once.
In your class definition you declare two pointers using the type int (int *pa,*pb), but in your constructor numPair::numPair(int a, int b) you are creating two new pointer declarations (int* pa and int* pb) that only exist within the constructor. From within your class constructor, you can reference its members by name without declaring a type every time, since you already declared them in the class definition. This is why your solution #1 works for you.
Additionally, in your original code, you are leaking the memory allocated on the heap for the values because you do not call delete on those pointers.
I am making an array of 4 std::list. But when I try to access the array's first list's first A object and call the callMe() method on it I get a weird output.
Now 2 things could have happened:
Either the list was empty.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))).
Details of the above cases:
If no A object was created then I should have got an exception. But I didn't get any exception so I am assuming that an A object was created.
So if an A object was indeed created, then the constructor should have been called.
What am I missing?
#include <iostream>
using namespace std;
class A {
public:
A() {
cout<<"Constructor called"<<endl;
x=20;
}
void callMe();
private:
int x;
};
void A::callMe() {
cout<<"Value of x = "<<x<<endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
(*(arrayOflistOfA[0].begin())).callMe();
}
The output is:
Value of x = 0
but the output should have been:
Constructor called
Value of x = 20
If no A object was created then I should have got an exception.
Not true.
But I didn't get any exception so I am assuming that an A object was created.
Don't assume. Find out. Go to some documentation for begin() and for iterators and discover that you do not get an exception, you get UB.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))). [And] if an A object was indeed created, then the constructor should have been called.
That's right. Clearly you have no elements in the list.
And we know that, because there is no code in your program that adds elements to the list.
Also you should not dynamically allocate containers unless you really, really need to (I've never found a need to).
You aren't actually populating the list with any values. I tested the below code and include a commented explanation.
#include <iostream>
#include <list>
using namespace std;
class A {
public:
A();
void callMe();
private:
int x = 0;
};
A::A()
{
cout << "Constructor called" << endl;
x = 20;
}
void A::callMe() {
cout << "Value of x = " << x << endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
cout << arrayOflistOfA->size() << endl; // As you can see, size is 0 here - you created a list of nulls.
for (int i = 0; i < size; i++)
{
arrayOflistOfA->push_back(A());
}
// The below code demonstrates how to loop through the array once it's populated.
list<A>::iterator it;
for (auto& a : *arrayOflistOfA)
{
a.callMe();
}
return 0;
}
I got the answer to my question. Firstly I tried to run this code on my mac with GNU C++ compiler but when I ran the same code on an iPhone simulator it crashed. So as #PaulMcKenzie mentioned, I was indeed trying to dereference an invalid iterator.
or Mrs.,
in C++, I'm thinking about using a subroutine to define all my pointers first declared in my main body. I know it can be done by using functions to return one pointer each time. Hence, I still want to do it in a subroutine. I googled much and haven't found a answer yet. Your help is appreciated.
An sample c++ code is as:
#include <iostream>
using namespace std;
void testsub(int* k3d)
{
k3d= new int [10];
cout<<"test 0 "<<k3d[0]<<endl;
}
int main ()
{
int* i3d=0;
testsub(i3d);
cout<<"test 1 "<<i3d[0]<<endl;
}
I hope the i3d in the main body can be used after the dummy pointer k3d has been defined in the subroutine.
Thanks a lot in advance.
The pointer needs to be passed in by reference, otherwise you're just changing a local copy of that pointer.
void testsub(int*& k3d)
Also you need to call delete[] after the coutstatement, to avoid memory leaks:
delete [] i3d;
Alternatively, you could return a pointer from a subroutine.
#include <iostream>
int* testsub()
{
int* ptr = new int[10];
std::cout << "test 0 " << ptr[0] << std::endl;
return ptr;
}
int main()
{
int *i3d = testsub();
cout << "test 1 " << i3d[0] << endl;
delete[] i3d;
return 0;
}
Or use a std::vector to hold a collection of integers. In this case you don't need to worry about memory allocations/deallocations too.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> i3d(10);
std::cout << "test 1 " << i3d[0] << std::endl;
return 0;
}
My struct has a vector of integers. However, when dynamically creating an instance of the struct, I can't seem to access the vector.
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
typedef struct {
vector<int> intList;
} astruct;
int main()
{
astruct* myStruct = (astruct*) malloc(sizeof(astruct));
myStruct->intList.push_back(100);
cout << "Hello world!" << endl;
free(myStruct);
return 0;
}
Attempting to add 100 to the struct's vector crashes the program. Hello world! is never shown. What's going on?
Your vector is never initialized as you simply cast an allocated memory region to a astruct*, therefor the constructor of your struct and as consequence the constructor of std::vecotr is never called. Use the new operator instead.
astruct* myStruct = new astruct();
myStruct->intList.push_back(100);
delete myStruct;
You should not use malloc()/free() in C++ program, especially for creating C++ object, unless you know what you are doing. So use new/delete instead:
int main()
{
astruct* myStruct = new astruct;
myStruct->intList.push_back(100);
cout << "Hello world!" << endl;
delete(myStruct);
return 0;
}
There may be other examples, but this is the one I just came across.
#include <iostream>
using namespace std;
class Student
{
public:
int x;
};
int main()
{
Student rts;
Student* heap = new Student;
cout << rts.x << endl; // prints out random integer
cout << heap->x << endl; // prints out 0
}
Is there any good reason or logic to understand behind this?
In this instance I think it is just coincidence that the heap is already zeroed in the memory that is allocated.
You can read more in the answers to this similar question
Always initialize your variable to something meaningful. Else its allowed to take any values at random.
class Student {
public:
int x;
Student(): x(0) {}
};