I have tried this piece of code mentioned below, I'm not understanding why *p need to be pass to doOperation() function. Why can't we pass p? What is the difference between the two?
doOperation(*p); // need explanation why derefencing
doOperation(p); // Gives compilation error
int main()
{
int *p = getpointer();
std::cout << "p:" << *p << std::endl;
doOperation(*p); // Why this has to be pass as a pointer when the function parameter as reference
return 0;
}
void doOperation(int &ptr)
{
//std::cout << "ptr:" << ptr << std::endl;
}
int *getpointer()
{
int *ptr = new int[10];
int i;
for (i=0; i <= 10; i++)
{
*(ptr+i) = i;
}
return ptr;
}
You've declared p as an integer pointer. The function doOperation takes an int reference as a parameter. doOperation(*p) means that you're dereferencing the pointer (which points to the first element in the array) and passing it to the function. Also as #dxiv have pointed out, in the function getpointer, the loop initializes 11 elements instead of 10. you can solve this by just changing <= to <.
If you want to pass the pointer by reference instead, the function doOperation can look like this:
void doOperation(int *&ptr)
{
std::cout << "ptr:" << ptr << std::endl;
}
Then you can just pass the pointer as an argument like this:
doOperation(p);
Output:
p:0
ptr:0x2b71550
The code after the changes should look like this:
#include <iostream>
void doOperation(int *&ptr)
{
std::cout << "ptr:" << ptr << std::endl;
}
int *getpointer()
{
int *ptr = new int[10];
int i;
for (i=0; i < 10; i++)
{
*(ptr+i) = i;
}
return ptr;
}
int main()
{
int *p = getpointer();
std::cout << "p:" << *p << std::endl;
doOperation(p);
return 0;
}
Related
I can't use string because of task conditions, so it must be char*. There is problem with dynamic array in constructor. Error "'=': cannot convert 'char*' to 'char'"
#include <iostream>
class Line {
public:
const int Size = 10;
char* DynamicLines = new char[Size];
int counter = 0;
Line(char* otherline) {
if (counter < Size) {
DynamicLines[counter] = otherline;
counter++;
}
std::cout << "constructor called\n";
}
~Line() {
delete[] DynamicLines;
std::cout << "destructor called\n";
}
void Print();
};
void Line::Print() {
this->counter = 0;
std::cout << DynamicLines[counter] << "\n" << "length = ";
counter++;
}
void main()
{
char* temp = new char;
std::cin >> temp;
Line Fline(temp);
Fline.Print();
delete temp;
system("pause");
}
According to the C++ Standard the function main shall have the return type int
int main()
In this constructor
Line(char* otherline) {
if (counter < Size) {
DynamicLines[counter] = otherline;
counter++;
}
std::cout << "constructor called\n";
}
this statement
DynamicLines[counter] = otherline;
does not make a sense. In the left hand side of the assignment there is an object of the type char while in the right hand side there is an object of the type char *. So the compiler issues the error message.
You need to copy elements of one array into another array.
Also the condition of this if statement
if (counter < Size) {
always evaluates to true. So the statement also does not make a sense.
And in main this code snippet can result in undefined behavior because you allocated only one character
char* temp = new char;
std::cin >> temp;
but are trying to enter a string.
char *DynamicLines is pointer to an array of char. Therefore each entry in the array, is a char, not a char* (pointer).
Your constructor accepts a pointer to char which needs to be dereferenced, in order to access the char in the memory and store it in the array.
So:
Line(char* otherline) {
if (counter < Size) {
DynamicLines[counter] = *otherline; // Notice * in front, to get the value from the pointer
counter++;
}
std::cout << "constructor called\n";
}
Here I want to get rid of insert function by overloading [] and = operators.
By overloading [] operator, I have successfully returned the address of the required location where I want to insert the value.
#include<iostream>
using namespace std;
#define const maxSize = 30;
class ARRAY
{
private:
int *ar;
int end;
public:
ARRAY()
{
ar = new int[40];
end = -1;
}
void insert(int value)
{
end += 1;
ar[end] = value;
}
void insert(int value, int index)
{
if (index<30 && index >-1)
{
int tempEnd = end;
for (int i = end; i >= index; --i)
{
ar[tempEnd + 1] = ar[tempEnd];
tempEnd -= 1;
}
end += 1;
ar[index] = value;
}
else
cout << "\nOVERFLOW";
}
void remove(int index)
{
if (index >= 0 && index <= end)
{
for (int i = index; i < end; ++i){
ar[i] = ar[i + 1];
}
end -= 1;
//do something
}
else
cout << "\nNothing gonna happens";
}
void display()
{
for (int i = 0; i <=end; ++i)
cout << "\n" << ar[i];
}
int* operator[](int at)
{
if (at < 40){
end++;
return (&ar[at]);
}
}
//Here I want to do = operator overloading, How can I do this?
};
int main()
{
ARRAY arr;
arr.insert(1);
arr.insert(2);
arr.insert(3);
arr.insert(4);
arr.insert(5);
arr[5] = 10;
arr.display();
return 0;
}
You can achieve the desirable behavior by changing the return type of your operator[]:
int& operator[](int at)
In your original code it returns pointer to the array element, which, even if changed, does not do anything with the value stored in the array. With your original code, you could write something like this to change the element's value:
*(arr[5]) = 10;
which looks unobvious.
If you return reference instead of pointer, you can directly change the value it references to.
You do not need to overlaod the assignment operator '=' for your purpose. Only overload the access operator '[]'.
That should look something like this:
returntype& operator [](int indexvariable);
That is going to give you a reference to an instance of returntype and therefore you wont need to overload the assignment operator of your returntype in your case.
Then you can write:
arr[5] = 23;
You can achieve pretty much any desirable behavior with some trickery.
In your case, if you want some specific action for operator= (e.g. check bounds & insert a new element), you can introduce a helper class, that will hold a reference to an array and an index, and then overload the operator= for that class:
class ArrayIndex
{
ARRAY& array;
int index;
public:
ArrayIndex(ARRAY& a, int i) : array(a), index(i) {}
void operator=(int value)
{ array.insert(value,index); }
};
And of course you tweak your ARRAY's operator[] to return the ArrayIndex object.
If you don't want the insertion or any unusual actions, and only want to access the elements, then operator[] returning the reference (int&) will suffice.
Following the comment OP left on akexeykuzmin0's response, I suggest to alter your operator[] to return a handler to your element.
#include <iostream>
struct ARRAY
{
struct Handler
{
int* _ptr;
Handler(int* ptr) : _ptr(ptr) {}
int& operator*() { return *_ptr; }
operator int*() { return _ptr; }
int& operator=(int const& value) { *_ptr = value; return **this; }
};
int _value;
ARRAY(int n) : _value(n) {}
Handler operator[](size_t) { return Handler(&_value); }
};
int main() {
ARRAY arr(42);
std::cout
<< std::hex << &arr._value << "\n"
<< std::dec << arr._value << "\n"
<< *arr[0] << "\n\n";
arr[0] = 137;
std::cout
<< std::hex << &arr._value << "\n"
<< std::dec << arr._value << "\n"
<< *arr[0] << "\n\n";
int* pvalue = arr[0];
*pvalue = 0;
std::cout
<< std::hex << &arr._value << "\n"
<< std::dec << arr._value << "\n"
<< *arr[0] << "\n\n";
}
Output
g++ -std=c++17 -O2 -Wall -Werror main.cpp && ./a.out
0x7ffd682844f0
42
42
0x7ffd682844f0
137
137
0x7ffd682844f0
0
0
Live demo on coliru
This handler can be implicitly converted to a int* and you can overload the operator= on it.
I am writing an assignment that requires me to implement my own (basic) vector class. One unusual requirement, is that we must provide a function which gives the sum of all elements in the vector. This function should cache the sum, so subsequent calls can be answered in constant time if the vector has not changed.
The problem I am having is trying to figure out when it has changed.
#include <iostream>
class MyVector {
int* v;
int size;
int totalSum;
bool upToDate;
public:
MyVector(int size) : size{size}, totalSum{0}, upToDate{false} {
v = new int[size];
for(int i = 0; i < size; i++) {
v[i] = 0;
}
}
// Set - should only be called as an lvalue
int& operator[](unsigned int i) {
upToDate = false;
std::cerr << "Set\n";
return v[i];
}
// Get - should only be called as an rvalue
int operator[](unsigned int i) const {
std::cerr << "Get\n";
return v[i];
}
// Get sum of array -- result is cached for performance
int sum() {
if(!upToDate) {
upToDate = true;
totalSum = 0;
for(int i = 0; i < size; i++) {
totalSum += v[i];
}
}
return totalSum;
}
};
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
I've provided two overloaded versions of the [] operator -- one for getting and one for setting. Whenever the setting version of the operator is invoked, I assume that the vector is being changed.
# Output
Set
Set
Set
Sum 6
Set
First element is 1
Sum 6
However, it seems the setting version of the operator is always being called, even when it is being used as an rvalue.
How do I overload the [] operator correctly to distinguish between its use for getting and setting?
Instead of returning a reference to the stored int directly, you can return a thin proxy wrapper around that reference, which can watch for changes. In the majority of cases, the compiler should inline it and optimize it away (you can try to benchmark it and compare).
The wrapper class:
class Item {
int &value;
MyVector &myVector;
public:
Item(int &value, MyVector &myVector) : value(value), myVector(myVector) {}
Item& operator=(int newvalue) {
std::cerr << "Set\n";
value = newvalue;
myVector.upToDate = false;
return *this;
}
// TODO: Reimplement also operators like +=, -=, etc
// You can use boost helpers for that.
operator int() const {
std::cerr << "Get\n";
return value;
}
};
Changes to MyVector:
class MyVector {
// ...
Item operator[](unsigned int i) {
return Item(v[i], *this);
}
const int operator[](unsigned int i) const {
std::cerr << "Const Get\n";
return v[i];
}
// ...
}
It can be used exactly the same way:
int main() {
MyVector mv(3);
mv[0] = 1;
mv[1] = 2;
mv[2] = 3;
std::cout << "Sum " << mv.sum() << "\n";
int first = mv[0];
std::cout << "First element is " << first << "\n";
std::cout << "Sum " << mv.sum() << "\n";
}
I want to pass array to function by reference. This function will dynamically allocate the elements.
This code give me an error message: access violation
#include <iostream>
using namespace std;
void func(int* ptr)
{
ptr = new int[2];
ptr[0] = 1;
ptr[1] = 2;
}
void main()
{
int* arr = 0;
func(arr);
cout << arr[0] << endl; // error here
}
C++ passes arguments by value. If you want to pass an int pointer by reference, you need to tell C++ the type is "reference to pointer to int": int*&.
Thus, your function prototype should be
void func(int*& ptr);
Note that you are still not handling pointers or references to arrays, but rather a pointer to the first element, which is close but not the same.
If you really wanted to pass an array of size 2 by reference, your function prototype would look like this:
void func(int(&my_array)[2]);
First of all function main shall have return type int.
As for your question then either you have to pass the pointer by reference or pass pointer to pointer. Or you could simply return pointer from the function.
Here is a demonstrative program that shows the three approaches. Take into account that you could use smart pointer std::unique_ptr.
#include <iostream>
int * func()
{
int *ptr = new int[2];
ptr[0] = 1;
ptr[1] = 2;
return ptr;
}
void func( int **ptr )
{
delete [] *ptr;
*ptr = new int[2];
( *ptr )[0] = 3;
( *ptr )[1] = 4;
}
void func( int * &ptr )
{
delete [] ptr;
ptr = new int[2];
ptr[0] = 5;
ptr[1] = 6;
}
int main()
{
int *arr = func();
std::cout << arr[0] << ", " << arr[1] << std::endl;
func( &arr );
std::cout << arr[0] << ", " << arr[1] << std::endl;
func( arr );
std::cout << arr[0] << ", " << arr[1] << std::endl;
delete [] arr;
}
And one more example of using std::unique_ptr
#include <iostream>
#include <memory>
std::unique_ptr<int[]> func()
{
std::unique_ptr<int[]> p( new int[2] );
p[0] = 1;
p[1] = 2;
return p;
}
void func( std::unique_ptr<int[]> &p )
{
p.reset( new int[2] );
p[0] = 3;
p[1] = 4;
}
int main()
{
std::unique_ptr<int[]> p = func();
std::cout << p[0] << ", " << p[1] << std::endl;
func( p );
std::cout << p[0] << ", " << p[1] << std::endl;
}
As you see in this case you need not bother about calling operator delete []
I'm new to C++, and I'm having significant trouble with creating an array of objects using a pass by pointer and reference. This is not the actual code; it's an example of what the code essentially does.
#include <iostream>
class MyClass
{
public:
MyClass();
static int doStuff(MyClass *&classArray);
void print_number();
private:
int number;
};
MyClass::MyClass()
{
}
int MyClass::doStuff(MyClass *&classArray)
{
int i = 0;
for (i = 0; i < 10; i++) {
*classArray[i].number = i;
}
return i;
}
void MyClass::print_number()
{
std::cout << number << "\n";
}
int main(void)
{
MyClass *test = nullptr;
int p = MyClass::doStuff(test);
std::cout << p << '\n';
for (int i = 0; i < 10; i++) {
test[i].print_number();
}
return 0;
}
When compiled, this gives a segmentation fault.
This is how you do it (don't forget do delete classArray with delete[] at the end of your program or destructor:
new operator has to have default constructor, if you want to use non-default it is easier to create copy constructor, then a temporary object and copy.
#include <iostream>
class MyClass
{
public:
MyClass();
MyClass(int x, int y);
MyClass(MyClass &OldClass);
static int doStuff(MyClass *&classArray, int Size, int x, int y);
void print_number();
private:
int number, x, y;
};
MyClass::MyClass()
{
number = 0;
x = 0;
y = 0;
}
MyClass::MyClass(int x, int y)
{
number = 0;
this->x = x;
this->y = y;
}
MyClass::MyClass(MyClass &OldClass)
{
this->number = OldClass.number;
this->x = OldClass.x;
this->y = OldClass.y;
}
int MyClass::doStuff(MyClass *&classArray, int Size, int x, int y)
{
if (Size > 0)
{
classArray = new MyClass[Size];
for (int i = 0; i < Size; i++)
{
classArray[i] = MyClass(x, y);
classArray[i].number = i;
}
return Size;
}
else
return 0;
}
void MyClass::print_number()
{
std::cout << number << " " << x << " " << y << "\n";
}
int main(void)
{
MyClass *test = nullptr;
int p = MyClass::doStuff(test, 10, 5, 6);
std::cout << p << '\n';
for (int i = 0; i < p; i++) {
test[i].print_number();
}
delete[] test;
std::cin.get();
return 0;
}
It is not working because you need to allocate the array, as the function is trying to access elements of an array which has yet not been initialized to hold that amount of elements. You can do this by
MyClass *test = new MyClass[array_size];
Or
MyClass test[array_size];
Or by using a resizable container such as std::vector, and changing the function parameters accordingly
*classArray[i].number = i;
You called doStuff with a null pointer, so classArray is null and is not an array. Dereferencing a null pointer results in undefined behavior and on most implementations you'll usually get a crash.
You're also dereferencing something that's not a pointer so this code will not even compile. The error I get is:
main.cpp:23:9: error: indirection requires pointer operand ('int' invalid)
*classArray[i].number = i;
^~~~~~~~~~~~~~~~~~~~~
Presumably this is just because, as you say, the code you're showing is not your real code and classArray[i].number corresponds to a pointer in your real code. But I thought I'd point this out anyway, just in case.
Given the context of your code, here's a working example of your code:
#include <iostream>
class MyClass
{
public:
MyClass() {}
static int doStuff(MyClass*& classArray, size_t sz)
{
int i = 0;
for (; i < sz; i++) {
classArray[i].number = i;
}
// not sure what you want here, but this will return sz+1 if sz>0
return i;
}
void print_number()
{
std::cout << this->number << std::endl;
}
private:
int number;
};
int main(void)
{
MyClass* test = new MyClass[10];
int p = MyClass::doStuff(test, 10);
std::cout << p << '\n';
for (int i = 0; i < 10; i++) {
test[i].print_number();
}
delete[] test;
return 0;
}
Though as others have pointed out, you are using C++, while it's a great exercise in understand how to pass pointers and arrays around, you might find the STL and C++stdlib contain a lot of these types of idioms in an 'easier to understand context'.
Here's your code with some C++ STL:
#include <iostream>
#include <vector>
class MyClass
{
public:
MyClass() {}
MyClass(int i) : number(i) {}
static int doStuff(std::vector<MyClass>& classArray, size_t sz)
{
int i = 0;
for (; i < sz; i++) {
classArray.push_back(MyClass(i));
}
// not sure what you want here, but this will return sz+1 if sz>0
return i;
}
void print_number()
{
std::cout << this->number << std::endl;
}
private:
int number;
};
int main(void)
{
std::vector<MyClass> test;
int p = MyClass::doStuff(test, 10);
std::cout << test.size() << '\n';
// can use iterators here if you want
std::vector<MyClass>::iterator itr = test.begin();
for (; itr != test.end(); itr++) {
itr->print_number();
}
return 0;
}
Hope that can help.