Arrays of Pointers with overloaded operators - c++

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

Related

Passing arrays of pointers in 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;
}

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.

Return struct created from new struct within function

In this code, does the array pointer in the struct returned from the function point to the same block of memory that was defined with the new struct?
#include <iostream>
#include <math.h>
struct Arr
{
const int Col;
const int Row;
double* CAR{ new double[Col * Row] };
Arr(int y, int x) : Col(x), Row(y) {}
void Del() { delete[] CAR; }
int Indx(int y, int x) { return (x + y * Col); }
int Size() { return Col * Row; }
void Print(std::string title);
};
void Arr::Print(std::string title)
{
std::cout << title << '\n';
for (int I = 0; I < Row; I++)
{
for (int In = 0; In < Col; In++)
{
std::cout << CAR[Indx(I, In)] << " / ";
}
std::cout << '\n';
}
}
const Arr retfunc(std::string h, Arr& a, Arr& b)
{
Arr* temp = NULL;
if (h == "Had")
{
temp = new Arr(a.Row, a.Col);
for (int I = 0; I < a.Row; I++)
{
for (int In = 0; In < a.Col; In++)
{
temp->CAR[temp->Indx(I, In)] = a.CAR[a.Indx(I, In)] * b.CAR[b.Indx(I, In)];
}
}
} Arr T = *temp; return T;
}
int main()
{
int val = 5;
Arr a(2, 2);
Arr b(2, 2);
for (int I = 0; I < 2; I++)
{
for (int In = 0; In < 2; In++)
{
a.CAR[a.Indx(I, In)] = 10.0 / val + In;
b.CAR[b.Indx(I, In)] = 8.0 / val + In;
}
}
a.Print("a");
b.Print("b");
Arr S = retfunc("Had", a, b);
S.Print("S");
S.Del();
}
So essentially then, does calling delete on S clear the same memory that was allocated in retfunc?
You should just have a return *temp at the end of retfunc which is declared to return an Arr object. Once this is fixed, S.Del() correctly releases the memory block allocated in retfunc.
Yet this is terrible code. You fail to release the blocs allocated in a and b object. Not an error because the end of the program will release them, but this is a recipe for memory leaks. Moreover, you have a manual allocated memory block in constructor, but no explicit copy constructor nor assignment operator. If you write:
Arr c = a;
both c and a will share the same CAR array which may or not be what you want.
Long story short, I think that this is not a blatant error but at least an antipattern.
For starters the function retfunc has a memory leak because the object temp dynamically allocated within the function is not freed.
As the class does not have an explicit copy constructor then in this declaration
Arr T = *temp
there is used member-wise copying of data members of the object temp to the object T. The value of the pointer CAR of the object temp will be copied in the pointer CAR of the object T and will be a valid pointer due to the life-time of the dynamically allocated object temp.
When within a class there is dynamically allocated memory then you need to write an explicit destructor, copy constructors for lvalues and rvalues and copy assignment operators for lvalues and rvalues.

Can C++ pass empty pointer to a function?

For example, I want to declare pointer to array and to don't wanna initialize it. Then, I want pass it to a function and initialize it exactly in function. How can I do it in C++?
void F(int *B, const int& N) {
B = new int[N];
for (int i = 0; i < N; ++i) B[i] = i;
}
int main() {
int N = 4;
int *B = nullptr; // doesn't work
F(*B, N);
for (int i = 0; i < N; ++i)
cout << B[i] << endl;
return 0;
}
It evokes/produces error corresponds to the problem that B has no reference to point and, therefore he can't initialize array.
error: Process finished with exit code 11
The pointer you pass is a copy of the original pointer. When you modify B in F, B i main() remains the same.
You need to pass the pointer by reference or pass a pointer to the pointer:
void F(int*& B, const int& N) {
B = new int[N];
for (int i = 0; i < N; ++i) B[i] = i;
}
int main() {
int N = 4;
int *B = nullptr; // doesn't work
F(B, N); //no operator here, just pass the pointer by reference
for (int i = 0; i < N; ++i)
cout << B[i] << endl;
return 0;
}
or
void F(int** B, const int& N) {
*B = new int[N];
for (int i = 0; i < N; ++i) (*B)[i] = i;
}
int main() {
int N = 4;
int *B = nullptr; // doesn't work
F(&B, N); //need address-of operator
for (int i = 0; i < N; ++i)
cout << B[i] << endl;
return 0;
}
Also, since you decided to use manual memory management, you are also responsible to release the memory acquired with new. This is not necessary if you use std::vector as your container instead of raw pointer (or std::unique_ptr or other containers).
for (int i = 0; i < N; ++i)
cout << B[i] << endl;
delete[] B; //release memory after use
return 0;
You have at least two problems.
The first in in the call where you use *B. *B is the same as B[0], which means you're attempting to pass a single int element to the function. But since B is a null pointer, the dereference will lead to undefined behavior.
Correct (to fit the shown function signature) would be plain B:
F(B, N);
The second problem is that passing arguments to functions by default is done by value. Which means that the value of B is copied into the local variable B inside the function F.
When you assign to B in the function you only change the local copy, and the original value in the main function will be unmodified.
To solve this you need to pass B by reference:
void F(int*& B, const int N) { ... }

Array Class Printout of the array

I am trying to create a member function which print out the array that I control, but I am running into Seg fault. Any help would be really useful!
Here is my header file, all the code in there work except the last member function.
#include <iostream>
#include <assert.h>
using namespace std;
#ifndef _ARRAY_H
#define _ARRAY_H
template<class T>
class Array{
private:
T *a;
int length;
public:
// constructor
Array (int len){
length = len;
a = new T[length];
for (int i = 0; i < len; i++){
a[i]=0;
}
}
// destructor
~Array()
{delete[] a;}
// operator overload
T& operator [](int i){
assert (i>=0 && i < length);
return a[i];
}
// operator overload
Array<T>& operator=(Array<T> &b){
if (a !=nullptr) delete[] a;
a = b.a;
b.a = nullptr;
length = b.length;
return *this;
}
//get the length of the array
int arraylength(){
return length;
}
//------------------This below is where I am having issue --------//
//print out the array
Array<T> printarray(){
for (int i = 0; i < length; i++){
cout << a[i];
}
}
};
int main();
#endif
This is my main file
#include <iostream>
#include "../include/array.h"
using namespace std;
int main(){
// initialize array
Array <int> a(5);
Array <int> b(5);
// put stuff into array
for (int i = 0; i< a.arraylength(); i++){
a[i] = i;
}
// set b = a using operator overload
b = a;
// print out the result b array
for (int i = 0; i < b.arraylength(); i++){
cout << b[i] << endl;
}
a.printarray();
return 0;
}
Again. Thank you for the help, I am quite new to C++ and mostly self taught.
In this statement
b = a;
you have called operator= in which a pointer of a object was set to nullptr, but in printArray you don't check if a is not null, so you are accesing data for null pointer, it is undefined behaviour. Add the condition to check if array is not empty:
void printarray(){
if (!a) return; // <- array is empty
for (int i = 0; i < length; i++){
cout << a[i];
}
}
Secondly, return type of printArray should be void, you don't return any value in this function.
You should fix printarray by changing the return type to void and making it a const member function.
void printarray() const {
for (int i = 0; i < length; i++){
cout << a[i];
}
}
However, that is not the main problem in your code. The main problem is that you are not following the The Rule of Three.
You don't have copy constructor.
You have a copy assignment operator but it is not implemented properly.
The line
b = a;
causes problems downstream that can be fixed by following The Rule of Three.
Here's an implementation of the copy assignment operator function that should work.
// Make the RHS of the operator a const object.
Array<T>& operator=(Array<T> const& b)
{
// Prevent self assignment.
// Do the real assignment only when the objects are different.
if ( this != &b )
{
if (a != nullptr)
{
delete[] a;
a = nullptr;
}
// This is not appropriate.
// a = b.a;
// b.a = nullptr;
// b needs to be left untouched.
// Memory needs to be allocated for this->a.
length = b.length;
if ( length > 0 )
{
a = new T[length];
// Copy values from b to this.
for (int i = 0; i < length; ++i )
{
a[i] = b.a[i];
}
}
}
return *this;
}
Please note that you should implement the copy constructor also, and then use the copy swap idiam to implment the assignment operator.
Very relevant: What is the copy-and-swap idiom?