C++ Dereferencing Null ptr error? - c++

I looked before posting, but pardon me if my answer is elsewhere. As part of my homework, I need to create an array of pointers to objects (of different types, but they share a base class). Once the pointers are in the array I need to be able to call member functions on the objects to which they point. I'm able to do this for the first object, but after my program goes through the loop once, I get the following exception: "0xC0000005: Access violation executing location 0x00000000"
Below is my code. Thanks
int main()
{
Sales * publications[5]; //declare an array of pointers
for (int i = 0; i < 5; i++) {
if (i < 3)
publications[i] = new Book();
else
publications[i] = new Tape();
std::cout << std::endl << publications[i] << std::endl;
(*publications)[i].readData();
(*publications)[i].displayData();
}
for (int i = 0; i < 5; i++) { //delete the array to avoid memory leak
delete publications[i];
}
std::cout << std::endl;
system("pause");
return 0;
}
I have already tested the readData and displayData functions and they work just fine.

This:
(*publications)[i].readData();
Should be:
publications[i]->readData();

publications is an array of pointers.
(*publications)[i].readData();
In this code snippet, the order of operations is out of order. The * dereference operator is going to take precedence over the [] array syntax operator due to the parenthesis.
The first thing that is going to happen is publications (the array) is going to be dereferenced - not the element located at index i. This will always give you the first element in the array, as an array variable is just the address of the first element.
The second operation that takes place is that a byte offset (sizeof(Sales) * i)) is added to the memory address returned by the dereference. When the index i is 0, this is not a problem since there is no offset to add and an object exists at the calculated memory location. However, once you have an index not equal to 0, the calculated memory address does not point at a valid Sales object, so you may or may not crash, depending on what actually lies at the memory location.
The correct order of operations using the given operators is this:
(*(publications[i])).readData();
Using the -> operator is preferred instead:
publications[i]->readData();
Now, the [] array-syntax operator takes precedence, offsetting the address of the array to an element within the array, and then either *. or -> is used to dereference that element's pointer to reach the object, as expected.

Related

Can someone explain what this pointer refers to here?

I came across a prime number generator in which they used this line of code
bool *numberlist = new bool[size+1];
What does this create?
The code also has this in a for loop:
numberlist[i*j]=true;
Isnt numberlist a pointer? how can you iterate through it like an array.
To break it down, the first line of code bool *numberlist = new bool[size+1];
declare a dynamic bool arrays that have for size [size+1]. The code in the for loopnumberlist[i*j]=true;means that the element i*j is true. In C++ array decayed to a pointer "more specificaly to a pointer to the first element"(meaning that each time we use an array in a expression, we are actually using a pointer) when we are accessing element of an array using brace operator ([]) we are doing 2 things. One pointer arithemtic(because an array is stored sequentially in memory) and Two dereference the pointer(to access the value that the pointer points to).
The variable numberlist holds a pointer to an array of booleans of size size + 1.
You can access the elements by means of operator []. Pointer arithmetic applies here too as you are iterating through boolean elements in memory. In a for loop you could use:
for (size_t i = 0; i < size; i++) {
std::cout << "numberlist[ " << i << "] = " << numberlist[i] << std::endl;
}
If you are iterating through a 2D matrix, for example, it is normal to store items ordered by rows and use two for-loops to iterate through rows/columns. This might be the case with your numberlist.

Variable as reference not staying

So i read this thread and many others:
Function does not change passed pointer C++
Yet i still can't solve my issue.
I have a function declared like this:
void test(list<int*> *listNodes){
int v=5;
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
int *totry = *i;
cout << *totry;
cout << ",";
}
}
Wich works, and prints fine, by the i mean: the listNodes variable has 3 elements, all 5's. However, when this functions returns, the values are not updated. By that, i mean that the variable has trash. I call this function in another one like this:
void create(list<int*> listNodes){
test(&listNodes);
for(list<int*>::const_iterator it=listNodes.begin();
it!=listNodes.end(); it++){
int *show=*it;
cout << *show << '\n';
}
}
Again, in this function, the cout will output memory garbage instead of outputting the 3 fives.
Any ideas on how should i proceed to, when the function test comes back, i have the list populated?
The problem I believe you're thinking about (as opposed to other problems in this code) is not actually what you're thinking. The list DOES maintain its values, the problem is that the values it has are pointing to garbage memory.
When you do this:
int v=5;
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
You are putting three copies of the address of v into the list. You have declared v as a stack variable that only exists for the duration of this function. When you print the values pointed to by the elements of listNodes inside function test, that variable still exists in that memory location.
When you later print out the values pointed to by the elements of listNodes in function create, that variable has gone out of scope and has been used by something else, hence the garbage.
Here are two possible solutions to consider:
Use list<int> instead of list<int *>. If all you want to do is store a list of integers, this is the way to go.
If, on the other hand, you really need to store pointers to those integers, you'll need to allocate memory off the heap:
int* v = new int(); // allocate an int on the heap
*v = 5; // store 5 in that int
(*listNodes).push_back(v); // save the pointer to the allocated
// memory in *listNodes
etc
This is not very good in terms of modern c++, however, as you generally don't want to be handling raw pointers at all, but it illustrates the point I think you are struggling with.
In this code,
void create(list<int*> listNodes){
listNodes=teste(&listNodes);
… the formal argument listNodes is passed by value. That means that the function receives a copy of whatever was passed as actual argument in a call siste. Changes to this copy will not be reflected in the actual argument.
The call to teste won't call the test function, since it's a different name.
In a way that's good, because test is declared as a void function so it can't return anything.
But it's also bad, because it means that a very crucial piece of your code, the teste function that's actually called, isn't shown at all in your question.
The test function,
void test(list<int*> *listNodes){
int v=5;
(*listNodes).push_back(&v);
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
int *totry = *i;
cout << *totry;
cout << ",";
}
printf("\n");
}
… has a lot wrong with it.
Starting at the top, in C++ the pointer argument
void test(list<int*> *listNodes){
… should better be a pass-by-reference argument. A pointer can be null. That doesn't make sense for this function, and the code is not prepared to handle that.
Next, in
int v=5;
(*listNodes).push_back(&v);
… the address of a local variable is pushed on a list that's returned. But at that point the local variable ceases to exist, and you have a dangling pointer, one that used to point to something, but doesn't anymore. If the caller uses that pointer then you have Undefined Behavior.
Next, this loop,
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
… will work, but it needlessly has O(n2) complexity, i.e. execution time.
Just iterate with the iterator. That's what iterators are for. Iterating.
Summing up, the garbage you see is due to the undefined behavior.
Just, don't do that.

C++ referencing an array of structs

I'm new to using C++ for complicated programming. I've been sifting through some leftover, uncommented, academic code handed down through my department, and I've stumbled across something I have no real idea how to google for. I don't understand the syntax in referencing an array of structs.
Here is a trimmed version of what I'm struggling with:
typedef struct
{
double x0,y0;
double r;
} circle;
double foo()
{
int N = 3;
double mtt;
circle circles[N];
for (int i = 0; i < N; i++)
{
mtt += mtt_call_func((circles+i), N);
}
return mtt;
}
What does (circles+i) mean in this case?
EDIT: the function should have (circles + i), not (circle + i).
circles+i is equivalent to &circles[i]. That's how pointer arithmetic works in C++.
Why is there a pointer? Well, when you give the name of an array, in a context other than &circles or sizeof circles, a temporary pointer is created that points to the first member of the array; that's what your code works with. Arrays are second-class citizens in C++; they don't behave like objects.
(I'm assuming your circle+i was a typo for circles+i as the others suggested)
circle+i means "take a pointer circle and move it i times by the size of the object pointed to by it". Pointer is involved because the name of the array is a pointer to it's first element.
Apart from this you should initialize an integer counter variable that is used in loop:
for (int i = 0; i < N; i++)
^^^^
{
mtt += mtt_call_func( ( circles + i), N);
^ // typo
}
In C, as in C++, it is legal to treat an array as a pointer. So circles+i adds i times the size of circle to the address of circles.
It might be clearer to write &circles[i]; in this form, it is more obvious that the expression produces a pointer to the ith struct in the array.
Each vector you declare in stack it's actually a pointer to the first index, 0, of the vector. Using i you move from index to index. As result, (circles+i) it's the equivalent of &circles[i].
& means the address of the variable. As in your function call, you send a pointer which stores an address of a variable, therefore & is required in front of circles[i] if you were to change to that, as you need the address of the i index of the vector circles to run your function.
For more about pointers, vectors and structures check this out: http://pw1.netcom.com/~tjensen/ptr/pointers.htm
It should cover you through ground basics.

Copying values from one vector to another (from book)

Consider this piece of code.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int *> test;
vector <int *> v;
int *a = new int;
int *b = new int;
*a = 1;
*b = 2;
v.push_back (a);
v.push_back (b);
for (int i = 0; i < 2; ++i)
{
int n = *v[i];
test.push_back (&n);
}
cout << *test[0] << " " << *test[1] << endl;
delete a;
delete b;
return 0;
}
The problem's statement is:
"Given this code, answer the following questions:
Why does "test" vector contain only 2's?
How can we change for loop to copy properly (only code inside for loop)?"
I couldn't answer any of these questions, so a little bit of help will be appreciated.
Thanks in advance.
That code introduces dangling pointers. The body of the loop looks like this:
{
int n = *v[i];
test.push_back (&n);
}
The local variable n loses scope as soon as the loop body ends, so the pointer &n is now a dangling pointer. If it happens that test contains only 2's, that's just what randomly came out of what is undefined behavior.
If you want to "properly" copy the data over to test, you can change the for loop body to this:
{
int* n = new int;
*n = *v[i];
test.push_back (n);
}
Please take the "properly" with a grain of salt...
You push two the same pointers to n into test array. n equals the last element of your first array. Note that after control flow exited the loop, all pointers to n become invalid. So, in fact your test array contains invalid pointers, not pointers to 2s.
You should create a copy of each integer:
int* n = new int(*v[i]);
test.push_back (n);
Note also that you have memory leak here. Each int created using new should be later destroyed using delete.
The first question is a trick question: The vector contains pointers to a variable that no longer exists, and dereferencing that could cause pretty much any output. I imagine on some machines and compilers it prints all 2s however.
I can't understand what the exercise is trying to do (why does it use vectors of pointers for example) so I can't really help with how to solve the problem.
One way you could do it is by making test store by value:
First change the test vector to vector <int> test;
Then change the push_back to something like test.push_back (n); and finally the print statements to remove the now-unneeded * operators.
EDIT for comment:
First, I'm suspect of this book: It shouldn't be demonstrating undefined behavior or raw pointers to single builtin types. But you can change your loop body if you want:
for (int i = 0; i < 2; ++i)
{
int* n = new int;
*n = *v[i];
test.push_back (&n);
}
Note that both this will cause a memory leak unless you later delete those pointers, a problem that storing by value eliminates.
1) I think that the premise of the question is faulty. The loop adds two elements to test, each contains the address of the automatic variable n, the scope of which is limited to the body of the loop. It's not guaranteed that n will be allocated the same memory location in both passes through the loop, but I suppose that it's likely that most compilers will reuse the same location in both passes.
Moreover, n is out of scope at the output statement. So referencing the pointers in test to those memory locations is undefined. Again, there's a good chance that they will still contain the values assigned in the loop.
So, only if the same location gets reused for n in the second pass of the loop and that location has not been overwritten at the time the output statement is executed, will the output be "2 2". There is no guarantee of either of these premises.
2) To get the output "1 2" without changing anything outside the loop, one could change the definition of n to int& n = *v[i], which would be a single character change from the given code, though the end result is rather strange.
A simpler solution would be to eliminate the temporary n and simply test.push_back(v[i]).

Creating arrays on the heap and addressing them with pointers

I'm having trouble understanding the following bit of code that I was hoping would create an array on the heap and fill it with the characters 9 down to 0 (I know I could just index the array like a normal stack array with [] notation to do this but I'm doing it this way to try to understand pointers in more depth):
int *ptrHeapArray = new int[10];
for(int f=9; f>=0 ;f--)
{
*ptrHeapArray = f;
ptrHeapArray++;
}
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
It prints out compleletly unexpected values.
As I understand the above, the 'new' command creates an array on the heap and sends me back a pointer to the address where the array is. Since the pointer I assign (ptrHeapArray) is of int size I assumed I could use pointer post incrementing to navigate through the array. However the results indicate that my assumptions are wrong.
This got me to thinking that perhaps the pointer passed back by the 'new' keyword is just a pointer to the whole array and can't be used to step through the array for some reason.
So I tried creating another pointer to the pointer returned by the 'new' keyword and used that to do my array population:
int *ptrHeapArray = new int[10]; //array to hold FRANK data in 32 bit chunks
int *ptrToHeapArrayPointer = ptrHeapArray;
for(int f=9; f>=0 ;f--)
{
*ptrToHeapArrayPointer = f;
ptrToHeapArrayPointer++;
}
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
This worked fine.
Can anyone explain to me why I had to do this and couldn't just have used the pointer passed backed to me by the 'new' keyword?
Thanks
The line
ptrHeapArray++;
in your first for loop increments the pointer, such that it doesn't point to the beginning of the array anymore.
The line
int *ptrHeapArray = new int[10];
allocates the memory for 10 integers and points ptrHeapArray to the beginning of that memory. In your for loop you then move this pointer. When ptrHeapArray points to the third of the integers:
[0] [1] [2] [3] [4]
^ ^ ^
orig. | |
| +-- ptrHeapArray[2]
|
+-- ptrHeapArray now points here
then ptrHeapArray[2] would give you the integer at the position orignally numbered with 4.
You are modifying the pointer in code. After the first loop in the first snippet, the pointer will point to the end of the array rather than the beginning. To make things clearer, this would work too (not suggested but demonstrates the behavior):
int *ptrHeapArray = new int[10];
for(int f=9; f>=0 ;f--)
{
*ptrHeapArray = f;
ptrHeapArray++;
}
ptrHeapArray -= 10; // reset the pointer to its original location
for(int f=0; f<10; f++)
cout << ptrHeapArray[f] << "\n";
Your ptrToHeapArrayPointer is misnamed, it is just a standard int ptr that you've pointed to the same place as ptrHeapArray. If you renamed it to currentPositionPtr your code might make more sense to you.
When you do ptrHeapArray++ it inscrements ptrHeapArray. When you come to print out the data ptrHeapArray no longer points to the start of the array.
The problem is that in your first example ptrHeapArray is initially set to the beginning of the array. As you iterate through your loop you are incrementing the pointer, and by the end of the for loop you are pointing to the last element in the array. When you go through the for loop to display all of your values, you are indexing to values past the end of the array since ptrHeapArray is pointing to the last element in the array you allocated.
It is also important to remember, that you should probably make sure not to loose the original pointer you got back from using the new operator so that you can properly free up the memory that was allocated on the heap.
In the first loop you incremented your pointer ptrHeapArray until the end of array. So after executing the first for loop your pointer is pointing to end of the array and not at the beggining. Hence, when you are trying to print the contents of the array, you are accessing invalid memory allocations and the behavior will be unexpected. In the second case, you are taking a copy of your starting address before assigning values to the array. So when you try to print the contents using the copy, it will be pointing to the beginning of the array.