Passing arrays of pointers in C++ - c++

Not sure what I'm doing wrong here. I'm trying to add a new element and up until the function ends it appears to have worked. But once I try to access anything in it after I get a segmentation fault.
This is just sample code I'm using to try and figure out what I'm doing wrong, with console output to help determine current values.
#include <iomanip>
#include <iostream>
using namespace std;
class foo
{
private:
int z;
public:
foo(int);
int getz();
void setz(int);
};
foo::foo(int zz)
{
z = zz;
}
int foo::getz()
{
return z;
}
void foo::setz(int zz)
{
z = zz;
}
void boo(foo** x, unsigned* n)
{
foo** b = new foo*[3];
for (int i=0; i<2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
foo** a = new foo*[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}

The problem is, how you pass your array to your function "boo".
As a general notice, please let me recap how we can use in/out parameters for functions. As you may have heard, we can
pass by value. A copy of the parameter will be made and the all assignmnets to such a variable, will not be available after the function returns.
pass by pointer. In the called function the the pointers will be dereferenced. Basically this is also pass by value. But here the address will be passed. And with dereferencing the address, the original value can be modified.
pass by reference (advised method). A reference to the original variable will be passed to the function and evrything can be handled as if interacting directly with the original variable.
You are passing the foo** as value. That is the reason why it will not work. Delete the parameter will work, but the assignment of x to b will not be visible to the outside world. And after the function "boo" returns, a will be deleted.
Let us look at the good all "swap" example.
// Call by value, will not work. "a" will be changed, but it is a copy
void swapv(int a, int b) {
int temp = a;
a = b;
b = tmp;
}
// Call by address(via pointer) will work. Dereferencing is necessary
void swapp(int *a, int *b) {
int temp = *a;
*a = *b;
*b = tmp;
}
// Call by reference. Recommended solution. Will simply work with same variable names
void swapr(int &a, int &b) {
int temp = a;
a = b;
b = tmp;
}
As you can see. The passing by reference approach is most simple.
Again, what you do is passing "foo**" by value. By the way, "n" is passed via pointer. If you use a typedef or usingstatement, it will get very obvious.
Look at the following piece of code using a using-alias statement.
using fooPtrPtr = foo**;
using fooPtr = foo*;
void boo(fooPtrPtr x, unsigned* n)
{
fooPtrPtr b = new fooPtr[3];
for (int i = 0; i < 2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
fooPtrPtr a = new fooPtr[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}
Now you can immediately see the problem. You see immediately that "x" is passed by value to "boo".
But this leads then directly to the recommended and easy solution. Pass it by reference. Like the below:
using fooPtrPtr = foo**;
using fooPtr = foo*;
void boo(fooPtrPtr& x, unsigned& n)
{
fooPtrPtr b = new fooPtr[3];
for (int i = 0; i < 2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
n++;
}
int main() {
fooPtrPtr a = new fooPtr[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, s);
cout << s;
cout << a[0]->getz();
return 0;
}
With pointers and pointers to pointers, using or typedef will be very helpful.
Very simple. And without using using the code will be not so easy to understand and could look like the below.
One ampersand "&" after foo** solves the whole problem.
void boo(foo**& x, unsigned& n)
{
foo** b = new foo*[3];
for (int i = 0; i < 2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
n++;
}
int main() {
foo** a = new foo*[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, s);
cout << s;
cout << a[0]->getz();
return 0;
}
And last but not least also the version with pass by address / via pointer. Then a lot of dereferencing is necessary, which makes code even harder to read:
void boo(foo*** x, unsigned *n)
{
foo** b = new foo*[3];
for (int i = 0; i < 2; i++)
b[i] = (*x)[i];
b[2] = new foo(5);
cout << (*x)[0]->getz() << (*x)[1]->getz();
delete[](*x);
*x = b;
cout << (*x)[0]->getz() << ' ' << (*x)[1]->getz() << ' ' << (*x)[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
foo** a = new foo*[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(&a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}
We can also use aliases to make this a little more readable, but still clumsy.
using fooPtrPtr = foo**;
using fooPtr = foo*;
void boo(fooPtrPtr* x, unsigned *n)
{
fooPtrPtr b = new fooPtr [3];
for (int i = 0; i < 2; i++)
b[i] = (*x)[i];
b[2] = new foo(5);
cout << (*x)[0]->getz() << (*x)[1]->getz();
delete[](*x);
*x = b;
cout << (*x)[0]->getz() << ' ' << (*x)[1]->getz() << ' ' << (*x)[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
fooPtrPtr a = new fooPtr[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(&a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}

Related

Why my C++ programme has stopped working?

I wrote C++ programme in vs code and When I run it, it ask me to enter the element value but when I enter the second time, it has stopped working. I don't know what the problem is but if you know the please help me to resolve the problem.
#include <iostream>
using namespace std;
class myArray {
public:
int total_size;
int used_size;
int* ptr;
myArray(int tsize, int usize)
{
total_size = tsize;
used_size = usize;
ptr = new int(tsize);
}
myArray() {}
void setvalue()
{
int n;
for (int i = 0; i < used_size; i++) {
cout << "Enter the element" << endl;
cin >> n;
ptr[i] = n;
}
}
void show()
{
for (int i = 0; i < used_size; i++) {
cout << "The element in array" << endl;
cout << ptr[i] << endl;
}
}
};
int main()
{
myArray(10, 2);
myArray a;
a.setvalue();
a.show();
return 0;
}
You used used_size and ptr without initializing them in a.setvalue(); and a.show();.
It seems
myArray(10, 2);
myArray a;
should be
myArray a(10, 2);
Also, as #Yksisarvinen points out,
ptr = new int(tsize);
should be
ptr = new int[tsize];
to allocate an array instead of single int.

C++ - what affects the order of call stack?

I'm so confused with the order of pushing and poping elements of a call stack. I created and initialized a static int* ptr in the void first(). NOTE: I know something unexpected may happen. But what confuses me is that what a call stack does to the recently used address(es).
When the program enters the function call first() in the level of second(), the varibale int a is at the address where int x was before. But after adding the line int z = 99; in the function second(), the variable a still stays in the address ptr points to.
Now something weird happens. If I get rid of the line std::cout << " &a = " << &a << std::endl;, *ptr will become 99 which means variable z is sitting at where x was when I debug or run it again .
I think, the ptr will never be put into the call stack cos it's a static variable and it stays in the data segment, which means ptr never affects the call stack. Therefore, the first-initialised variable in the function second() will be always sitting at where the first-initialised variable in the function first() was, no matter what.
I've got lost under this situation.
Without int z = 99:
void first() {
int x = 7;
static int* ptr = &x;
}
void second() {
int a = 5; // &a = (&x before)
int b = 1;
int c = 2;
int d = 3;
int e = 4;
std::cout << " &a = " << &a << std::endl;
first();
}
int main()
{
first();
second();
first();
}
With int z = 99:
void first() {
int x = 7;
static int* ptr = &x;
}
void second() {
int z = 99;
int a = 5; // &a = (&x before)
int b = 1;
int c = 2;
int d = 3;
int e = 4;
std::cout << " &a = " << &a << std::endl;
first();
}
int main()
{
first();
second();
first();
}
Without std::cout statement:
void first() {
int x = 7;
static int* ptr = &x;
}
void second() {
int z = 99; // &z = (&x before)
int a = 5;
int b = 1;
int c = 2;
int d = 3;
int e = 4;
first();
}
int main()
{
first();
second();
first();
}

Copying one array to another using pointers

I have to use pointers to copy values of one array to another. The problem is I'm not allowed to use'[ ]' operators, which makes this more difficult for me. Here is my attempt:
#include <iostream>
using namespace std;
void cpyia(int old_array[],int new_array[],int length){
int *p1 = old_array;
int *p2 = new_array;
int *x = p2;
for(int i=0 ; i<length ; i++){
p2 = x;
p2 = p2 + i;
p2 = p1 + i;
}
for(int i=0; i<5; ++i){
cout << p2[i] << endl;
}
}
int main() {
int a[5]={1,2,3,4,5};
int b[5];
cpyia(a, b, 5);
}
An easier way to do it would be to put p2[i] = p1[i] in the loop, but I cant do that. Any help is appreciated.
The standard way of implementing your function is as follow:
for(int i = 0; i < length; ++i)
*new_array++ = *old_array++;
To be a bit more explicit, it's the same as:
void cpyia(int old_array[],int new_array[],int length){
int *p1 = old_array;
int *p2 = new_array;
for(int i=0 ; i<length ; i++){
*(p2+i) = *(p1+i);
// another way: *(p2++) = *(p1++);
}
}
In real code, you would use std::copy before even thinking about rewriting such a simple thing yourself.
Here is a complete example:
#include <iostream>
#include <algorithm>
void cpyia(int old_array[],int new_array[],int length){
std::copy(old_array, old_array + length, new_array);
}
int main() {
int a[5]={1,2,3,4,5};
int b[5];
cpyia(a, b, 5);
// test results:
for (int index = 0; index < 5; ++index)
{
std::cout << a[index] << " <-> " << b[index] << "\n";
}
}
However, your question says that you are "not allowed to use" something, which sounds a lot like a homework assignment. In that case, you could look at possible implementations of std::copy to get an idea of how to do it. Here is one way:
void cpyia(int old_array[],int new_array[],int length){
int* first = old_array;
int* last = old_array + length;
int* d_first = new_array;
while (first != last) {
*d_first++ = *first++;
}
}
#include<iostream>
using namespace std;
int main() {
const int size = 5;
int arr1[size] = { 4,21,43,9,77 };
int arr2[size];
int *ptr_a = arr1;
int *ptr_b = arr2;
for (int i = 0; i < size; i++)
{
*(ptr_b + i) = *(ptr_a + i);
cout << *(ptr_b + i) << " ";
}
}

free dynamic array memory error: _BLOCK_TYPE_IS_VALID

I'm trying to free dynamic memory but I'm getting an error. I need some help pointing out which part of my code is causing the error.
I have destructor to free two dynamic arrays. Removing the destructor I get not errors.
Error: _BLOCK_TYPE_IS_VALID(pHEAD->nBlockUse)
Scores Class:
class Scores
{
private:
int numOfTest;
double *scoresArray = nullptr;
double scoreAvg;
double *scoreSort = nullptr;
public:
Scores(int);
~Scores();
void setNumOfTest();
int getNumOFTest();
void setScores();
double* getScores();
void setSort();
double* getSort();
void setScoreAvg();
double getScoreAvg();
};
Scores::Scores(int num)
{
scoresArray = new double [num];
scoreSort = new double[num];
numOfTest = num;
}
Scores::~Scores()
{
delete [] scoresArray;
delete [] scoreSort;
scoresArray = nullptr;
scoreSort = nullptr;
}
void Scores::setNumOfTest()
{
// Verify number of test scores is positive
while (numOfTest <= 0)
{
cout << "The number of test need to be postive." << endl;
cout << "Enter another number: ";
cin >> numOfTest;
}
}
int Scores::getNumOFTest()
{
return numOfTest;
}
void Scores::setScores()
{
double scores;
int size = getNumOFTest();
//scoresArray = new double[size];
for (int i = 0; i < numOfTest; i++)
{
cout << "Enter test score " << i + 1 << ": ";
cin >> scores;
// Verify if score enter is positive
while (scores < 0)
{
cout << "Negative scores are not allowed." << endl;
cout << "Enter another score for this test: ";
cin >> scores;
}
scoresArray[i] = scores;
}
}
double* Scores::getScores()
{
//double *sa = scoresArray;
//return sa;
return scoresArray;
}
void Scores::setSort()
{
int size = getNumOFTest();
//scoreSort = new double[size];
scoreSort = getScores();
for (int i = 0; i < size; i++)
{
int smallPos = i;
double smallest = scoreSort[smallPos];
for (int j = i + 1; j < size; j++)
{
if (scoreSort[j] < scoreSort[smallPos])
{
smallPos = j;
smallest = scoreSort[smallPos];
}
}
scoreSort[smallPos] = scoreSort[i];
scoreSort[i] = smallest;
}
}
double* Scores::getSort()
{
//double *ss = scoreSort;
//return ss;
return scoreSort;
}
void Scores::setScoreAvg()
{
int size = getNumOFTest();
for (int i = 0; i < size; i++)
{
scoreAvg += scoresArray[i];
}
scoreAvg /= size;
}
double Scores::getScoreAvg()
{
return scoreAvg;
}
Main:
int main()
{
int numOfTest;
cout << "How many test scores will you enter" << endl;
cin >> numOfTest;
Scores s(numOfTest);
s.setNumOfTest();
s.setScores();
s.setSort();
s.setScoreAvg();
double y = s.getScoreAvg();
double *x = nullptr;
x = new double[numOfTest];
x = s.getSort();
cout << "sort" << endl;
for (int i = 0; i < numOfTest; i++)
{
cout << x[i] << "\n";
}
cout << "avg" << endl;
cout << y;
delete[] x;
x = nullptr;
//s.Scores1();
return 0;
}
What you are seeing is a double delete. One obvious problem is that you are getting a pointer to object s's dynamically allocated array scoresArray here:
x = s.getSort(); // also leaks memory previously pointed at by x
then you call delete[] on it:
delete[] x; // calls delete[] on s.scoresArray
But the s object also calls delete[] on it in its destructor. That would cause a double deletion.
There could be other errors in the code besides this one.
Note that you could trivially avoid this problem by not using dynamic allocation explicitly, but relying on types such as std::vector<double> instead.
The problem is this line in Scores::setSort:
scoreSort = getScores();
getScores() returns scoresArray. So now scoreSort and scoresArray point to the same dynamically allocated block. When you then try to delete both of them, you're deleting the same block twice.
Instead of assigning the pointers, you should copy the contents of scoresArray into scoreSort, then sort scoreSort.

Arrays of Pointers with overloaded operators

When I run this code I get a bad_alloc error, Am I accessing the subscript operator wrong or something ? To me it makes sense that I go to the appropriate object, it gets returned and then the subscript operator should kick in ? By the way I want to use arrays and not vectors :)
class A{
public:
A(int size)
{
array = new int[size];
}
int& operator[](const int &i)
{
return array[i]
}
private:
int * array;
};
int main() {
A ** a = new A*[10];
for(int i = 0; i < 10; i++) {
a[i] = new A(10);
for(int l = 0; l < 10; l++) {
cout << a[i][l] << endl;
}
}
}
Thanks in advance
You need to dereference the pointer before you can call operator[]
cout << (*(a[i]))[l] << endl;
Here's what needs to happen, step by step:
A* pA = a[i];
A& rA = *pA;
int& val = rA[l];
cout << val;
Currently this happens:
A* pA = a[i];
A& ra = *(pA + l); // pA is indexed as an array of As - this is wrong
cout << ra; // invalid memory