I am new to c++ and trying to understand pointers. I read a example somewhere, which is like this:
#include<iostream>
#define N 5
using namespace std;
class Test {
int x, y;
public:
Test(int a, int b)
: x(a), y(b)
{
}
void print()
{
cout << x << " " << y << endl;
}
};
int main()
{
Test **arr = new Test*[N];
for (int i = 0; i < N; i++) {
arr[i] = new Test(i, i + 1);
}
for (int i = 0; i < N; i++) {
arr[i]->print();
}
}
So, in the line
Test **arr = new Test*[N];
as far as i understand, **arr means that it's a pointer to a pointer which points to a object. So when we assign it to new Test*[N], does it means *arr stores address of N object pointers?
And if it is correct, then how can i print the address of a object from the array of objects? let's say i want to print the address of the object Test[3]?
In modern C++, there's are better alternatives than having owning raw pointers, and better alternatives than manually new'ing up an array.
There are containers (such as std::vector), there are smart pointers (such as std::unique_ptr and std::shared_ptr).
Polymorphism needs to be done through a pointer (including smart pointer) or reference, but that is not a factor in the posted code.
The OP posted code has a memory leak, since it did not clean up the arr. In these kinds of small programs, memory leaks are sometimes handwaved away and ignored.
For the code you posted, I'd have done it this way, which eliminates the pointers altogether:
#include <iostream>
#include <vector>
using std::cout;
using std::vector;
constexpr int N = 5;
class Test {
int x;
int y;
public:
Test(int x_, int y_)
: x{x_}, y{y_}
{ }
void print() const {
cout << x << " " << y << "\n";
}
};
int main() {
vector<Test> arr;
for (int i = 0; i < N; i++) {
arr.emplace_back(Test{i, i+1});
}
for (auto const& test : arr) {
test.print();
}
}
I had to add a little const correctness. I relied on vector and have no need for a pointer or smart pointer, in this particular example.
In my last decade of programming C++, I've never needed to use a new or an owning raw pointer.
Raw pointers are still suitable for non-owning parameters which could be nullptr, and non-owning return values which could be nullptr. But since they are non-owning, there's no concern over memory management.
Update:
"... trying to understand pointers..."
Caveat. Unfortunately, my example of "how I'd do this kind of program" does not lend itself to the OP's goal of trying to understand pointers. That kind of topic is actually bit broad, and should be thoroughly covered in the first chapter or two of a good C++ book.
The answer to the first question is YES.
To the second question you can just send the pointer to cout without dereferencing it.
cout << arr[3];
Or use C's printf function:
printf("%p", arr[3]);
If you want to print it from the method, you use the this pointer:
void print()
{
cout << this << "- " << x << " " << y << endl;
}
Related
I try to make an array and take input and then simply showing the output on the screen but uses classes and objects, Here is my code:
#include<iostream>
using namespace std;
class array{
int ar[], n;
public:
void input();
int display();
}obj;
void array::input(){
cout<<"Enter item size: ";
cin>>n;
int ar[n]={};
for(int i=0; i<n; i++){
cout<<"Enter value at index "<<i<<" : ";
cin>>ar[i];
}
}
int array::display(){
cout<<"You Entered: ";
for(int i=0 ; i<n; i++){
cout<<ar[i];
}
}
int main(){
obj.input();
obj.display();
}
In the sample run, I entered 1 and 2 and I am expected to get 1 and 2.
Two problems in your code.
First int ar[] should not compile. I get the following error:
prog.cc:4:12: error: ISO C++ forbids flexible array member 'ar' [-Wpedantic]
int ar[], n;
^
Next, in array::input() you create a completely new array int ar[n]={}; which is also not valid c++. Array sizes must be compiletime constants. Moreover, this array shadows the member and is unrelated to it (apart from having the same name). So this ar is gone once you return from the method. You never write anything into the member ar.
If you dont know the size in advance you should use a std::vector:
#include <iostream>
#include <vector>
class array{
std::vector<int> ar;
public:
void input();
int display();
};
void array::input(){
std::cout << "Enter item size: ";
int n;
std::cin >> n;
ar.resize(n);
for(int i=0; i<n; ++i){
std::cout << "Enter value at index " << i << " : ";
std::cin >> ar[i];
}
}
int array::display(){
std::cout<<"You Entered: ";
for(int i=0 ; i<n; ++i){
std::cout << ar[i];
}
}
int main() {
array obj;
obj.input();
obj.display();
}
PS: read here why using namespace std; is bad practice: Why is "using namespace std" considered bad practice?
IMHO user463035818s answer is sufficient, but for all that OP asked me
how to fix this compiler issue.
The recommended fix would be by design i.e. like shown in user463035818s answer.
So, I want to elaborate how to fix the sample code of OP (with "minimal" changes). That might make obvious why user463035818s answer is the better one. (I repeated the link three times – it should be clear to everybody that I consider this as the better solution.)
The actual compiler error (or warning or feature accepted by compiler extension):
OP used int ar[] a C array as class member without denoting the size.
This is called Flexible array member but it is a C99 feature (not supported by the C++ standard).
The linked Wikipedia article provides a nice example:
struct vectord {
size_t len;
double arr[]; // the flexible array member must be last
};
To be clear, flexible array members don't provide automatic allocation. They just represent an array of arbitrary length. The programmer is responsible to grant sufficient storage for that array. Hence even in C, and with the resp. syntax adjustments, this code would have been broken.
Some C++ compilers adopt features from C as (proprietary) extension. That's the reason that OP got responses ranging from "On my side, it works."1 to "This is a compiler error." However, I would consider usage of such extensions as bad style in general. With different compiler settings or a different compiler, this might not work anymore.
1 This is not the only issue of OPs code. "It works" might be merely bad luck. OPs code has Undefined Behavior. One kind of Undefined Behavior is "It works" which is not the best one because programmer might believe that the code is fine.
A lot of higher level languages (Java, C#, Python) tries to cover memory allocation and storage management "under the hood" completely because it's not quite easy to make this always correct and consider every edge case sufficiently. This might cause an additional performance impact for the administration of memory. In C and C++, the programmer has ful control over memory allocation. It's both a blessing and a curse.
The standard library of C++ provides a variety of tools to make programmers allocation life easier.
For dynamic arrays, the tool of choice is the template class std::vector. It provides an overloaded operator[] which allows that it can be accessed just like an array. It provides methods like reserve() and resize(). The storage is internally managed.
I would strongly recommend to use std::vector but there is also the possibility to do it using new[] and delete[].
For this, the class array might look as follows:
class array {
int *ar; // a raw pointer for storage
int n; // the current size of array
public:
int display();
int* and int are plain old data types → implicit construction leaving them uninitialized. So, there really should be defined at least a default constructor.
array(): ar(nullptr), n(0) { }
The input() method has to ensure proper storage.
void input()
{
// release old memory (if there is one)
delete[] ar; ar = nullptr; n = 0;
// input
std::cout << "Enter item size: ";
std::cin >> n;
if (n <= 0) return;
ar = new int[n];
for (int i = 0; i < n; ++i) {
std::cout << "Enter value at index " << i << ": ";
std::cin >> ar[i];
}
}
When an instance of class array is deleted it should release the internal storage. Otherwise, the allocated memory pointed by ar will be orphaned and lost until process is terminated by OS. Such lost memory is called memory leak.
~array() { delete[] ar; }
Please, note that calling delete[] (or delete) with a nullptr is valid. Hence, no extra if (ar) is needed.
Finally, we have to obey the Rule of three. The compiler generates implicitly copy constructor and copy assignment operator which will copy the class array members by value. Copying a pointer by value does not mean that the contents (it points to) is copied. It just means copy the pointer (address value). Hence, an (accidental, unintended) copy of class array could result in two instances of class array which members ar point to the same memory. Once, one of them deletes that memory, the ar of the other becomes dangling i.e. points to released memory. (Bad!) If the other instance is destroyed also it will delete[] ar again. This is double deleting which is prohibited. (Bad again!)
One option could be to define copy constructor and copy assignment to handle this appropriately by making a deep copy of ar contents (with another new[]). However, if copy is not intended, an alternative is to just explixitly prohibit copy for class array:
array(const array&) = delete;
array& operator=(const array&) = delete;
};
Putting this althogether in array.cc:
#include <iostream>
class array {
int *ar; // a raw pointer for storage
int n; // the current size of array
public:
array(): ar(nullptr), n(0) { }
~array() { delete[] ar; }
array(const array&) = delete;
array& operator=(const array&) = delete;
void input();
void display();
};
void array::input()
{
// release old memory (if there is one)
delete[] ar; ar = nullptr; n = 0;
// input
std::cout << "Enter item size: ";
std::cin >> n;
if (n <= 0) return;
ar = new int[n];
for (int i = 0; i < n; ++i) {
std::cout << "Enter value at index " << i << ": ";
std::cin >> ar[i];
}
}
void array::display()
{
std::cout << "You Entered: ";
for (int i = 0; i < n; ++i) {
std::cout << ar[i];
}
std::cout << '\n';
}
int main()
{
array obj;
obj.input();
obj.display();
return 0;
}
Compiled and tested:
$ g++ -std=c++11 -Wall -pedantic array.cc && ./a.out
Enter item size: 1↲
Enter value at index 0: 2↲
You Entered: 2
$
Live Demo on coliru
The last sentence in OPs question is a bit unclear for me (although I assume it's just bad worded):
In the sample run, I entered 1 and 2 and I am expected to get 1 and 2.
Either input is 2 1 2 then output is 1 2.
Or input is 1 2 then output is 2.
Please note that array::input() expects first input of array::n but array::display() doesn't output array::n.
I have some issues getting my head around the idea of pointers. I know what they do in theory, but i have a problem understanding what they can actually be capable of. The basic exercises that i have seen are a bit vague in my opinion because they can be done without the actual subject. For example swapping two number, either by reference or by address.
#include <iostream>
using namespace std;
int main()
{
int a = 45, b = 35;
cout << "Before Swap\n";
cout << "a = " << a << " b = " << b << "\n";
int z = a;
a = b;
b = z;
cout << "After Swap with pass by reference\n";
cout << "a = " << a << " b = " << b << "\n";
}
//copied an example i saw online with pointers and modified it to get the
same result without needing them
One example on when using pointers could be better (assuming this is some sort of school context) would be if you want to make a function to swap the numbers instead of rewriting your code a lot.
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
return
}
If you tried using integers in the function instead of pointers, it'd swap the values locally, and not swap the variables in a greater context. What you could do to achieve the same results is use references instead (ie int &a, int &b), so you don't really need to use pointers, and in this example they aren't particularly useful.
Pragmatically, std::swap()is much more useful in modern c++, but the example above might be why the online tutorial uses pointers.
Pointers can be useful in other contexts, but I don't know if that's within the scope of your question, just perhaps what the tutorial was trying to achieve by using pointers.
Use the std::swap() method for swaping.
It is more efficient.
For your understanding if we write a function which swaps two values
so we have to pass the values by reference and not by value.
same is
the case with pointers.some time we need to swap value by pointers.
So if we pass values to this function from the main it will swap it.
void swap(int&,int&);
But here it won't work if we pass values to this function from the main.
void swap(int,int);
I wrote a simple piece of C++ code to pass addresses by reference.
I am passing the address of a variable (say y) and an array (say arr) to a class. Both arr and y will get modified inside the class. I want to have the modified values in my main().
Please find my question in the below piece of code as it is easier that way. Thanks.
#include <iostream>
using namespace std;
class A
{
public:
// Assign values to the array and increment _x.
void increment()
{
(*_x)++;
(*_arr)[0] = 1; // Q1. Is it safe to directly access the array like this.
(*_arr)[1] = 2; // Don't I have to allocate memory to the array ?
(*_arr)[2] = 3;
}
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
*_arr = arr;
}
private:
int* _x;
int** _arr;
};
int main()
{
int y = 9;
int arr[5];
int *pY = &y;
int *pArr = arr;
A *obj1 = new A(pArr, pY);
// This gives a compile time error. warning: initialization of non-const reference int *&' from rvalue `int *'
// A *obj1 = new A(&y); <-- Q2. Why does this give a Compile Time Error ?
obj1->increment();
cout << "y : " << y << endl;
cout << "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << endl;
cout << endl;
return 0;
}
In A::increment() function, I am directly assigning values to the array without
allocating memory. Is it safe to do ? If not, how can I allocate memory so that
I can still get the modified array values in main() ?
Why do I get a compile time error whey I pass &y to A's constructor ?
Thanks in advance.
Question 1
In A::increment() function, I am directly assigning values to the array without allocating memory. Is it safe to do ? If not, how can I allocate memory so that I can still get the modified array values in main() ?
Answer
Yes, it is safe.
Question 2
Why do I get a compile time error whey I pass &y to A's constructor ?
Answer
&y is not an lvalue. Hence, it cannot be used where the argument type is int*&.
Problem in posted code
*_arr = arr;
That is a problem since _arr has not been initialized to point to a valid memory. Using *_arr when _arr has not been initialized causes undefined behavior. You can change the type of _arr to:
int* _arr;
and simplify your code a little bit.
class A
{
public:
// Assign values to the array and increment _x.
void increment()
{
(*_x)++;
_arr[0] = 1; // Q1. Is it safe to directly access the array like this.
_arr[1] = 2; // Don't I have to allocate memory to the array ?
_arr[2] = 3;
}
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x),
_arr(arr)
{
}
private:
int* _x;
int* _arr;
};
without changing anything in main.
This is very rarely what you want; a T** is generally an array of arrays or else a pointer value that you want to modify in the caller’s scope. However, neither seems to be what you’re doing here.
It is safe to modify *_arr[0] if and only if _arr has been initialized to a array of non-const arrays, and (*_arr)[0] if and only if it has been initialized as a pointer to a non-const array. Neither appears to be the case here, but if it is, you probably want to give the array length explicitly.
In this example, &y is a constant. You can’t modify it, so you can’t pass it as a non-const variable. You can declare a pointer int *py = &y; and pass that. But consider whether that’s what you want to do.
By the way, it’s not good style to use identifiers that start with underscores, because by the standard, they’re reserved for the compiler to use.
You should tell us what you are trying to do. In my opinion it's nonsense using raw pointers/arrays and naked new/(missing?) delete in C++ without good reason. I would also like to note that it is not considered good practice using the _prefix for class members. Usually leading _ are used for std implementations. I recommend using m_prefix if you insist on one. And why do you give _arr the type int**? Is is supposed to be a 2D-Array? Additionally, it doesn't really make sense passing a pointer by reference. A pointer is already a pointer, if you know what I mean, just pass the pointer around.
I'm just going to assume that you are doing this to understand manual memory management or pointer arithmetics or - wait, right: Tell us what you are trying to do and why. Nevertheless, I don't understand what you have the class for:
#include <iostream>
void increment(int& x, int *arr, int sz)
{
++x;
for (int i = 0; i != sz; ++i)
{
// this just numbers the values respectively (starting at 1)
arr[i] = i + 1;
}
}
int main()
{
using namespace std;
int y = 9;
const int sz = 5;
int arr[sz];
increment(y, arr, sz);
cout << "y : " << y << '\n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "\n\n";
}
To answer your questions:
2. First thing first: I don't see any constructor that only takes one argument.
Read up on "Undefined Behaviour (UB)" starting point: What are all the common undefined behaviours that a C++ programmer should know about?
I can't repeat enough that I don't understand what you are going for and that makes it hard to give solid advice.
I tried fixing your version.. well its still terrible... I highly recommend on reading up on std::array, std::vector. Maybe on pointers, C-Style Arrays and how to pass C-Style Arrays as function arguments (note: for regular C++ programming you wouldn't be doing/using that, usually).
#include <iostream>
class A {
public:
// Assign values to the array and increment m_x.
void increment()
{
++(*m_x);
m_arr[0] = 1;
m_arr[1] = 2;
m_arr[2] = 3;
}
A (int* arr, int* x):
m_x(x), m_arr(arr)
{
}
private:
int* m_x;
int* m_arr;
};
int main()
{
using namespace std;
int y = 9;
int arr[5];
A obj1(arr, &y);
obj1.increment();
cout << "y : " << y << '\n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "\n\n";
A obj2(arr, &y);
obj2.increment();
cout << "y : " << y << '\n'
<< "[0]: " << arr[0] << "; [1]: " << arr[1] << "; [2]: " << arr[2] << "\n\n";
}
You should also read up un pointers/references and their differences
I am actually trying to make your programming life easier. Sorry for long answer.
In answer to your first question
In A::increment() function, I am directly assigning values to the
array without allocating memory. Is it safe to do ? If not, how can I
allocate memory so that I can still get the modified array values in
main() ?
you allocated memory in main(), in the line
int arr[5];
In terms of class design, you defined your class constructor to accept reference arguments, which means that an existing int* must be passed to each argument:
A (int* &arr, int* &x)
and you do so when you invoke the constructor:
A *obj1 = new A(pArr, pY);
so in this program, what you are doing is safe. A potential danger if you expect to use this class in another context would be if your arr array in main() contained fewer than 3 elements, since your increment() function initializes the third element of the array.
In answer to your second question
Why do I get a compile time error whey I pass &y to A's constructor ?
In your original constructor,
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
*_arr = arr;
}
you are dereferencing _arr before it has been initialized. One way to solve this would be to do this:
// Get the address of the Variable that is passed in main. x will now have &y2.
A (int* &arr, int* &x):
_x(x)
{
_arr = new (int*);
*_arr = arr;
}
// Destructor
~A ()
{
delete _arr;
}
As an aside, you also use new in main(). Whenever you use new, you should also use delete to avoid a memory leak. So at the bottom of your program, before the return statement, add the following:
delete obj1;
I'm teaching myself C++ and had some questions about arrays and pointers. My understanding is that arrays are really just pointers, however, arrays are address constants which cannot be changed.
If this is the case, I was wondering why in my function show2() I was able to change the address of the pointer list. Unlike variables, I thought arrays are passed by reference so I was expecting a compiler error when calling function show2() since I incremented the address of list. But the code works just fine. Can someone please explain?
Thank you!
#include<iostream>
#include<iomanip>
using namespace std;
void show1(double *list, int SIZE)
{
for(int i=0; i < SIZE; i++)
{
cout << setw(5) << *(list+i);
}
cout << endl;
return;
}
void show2(double *list, int SIZE)
{
double *ptr = list;
for(int i=0; i < SIZE; i++)
cout << setw(5) << *list++;
cout << endl;
return;
}
int main()
{
double rates[] = {6.5, 7.2, 7.5, 8.3, 8.6,
9.4, 9.6, 9.8, 10.0};
const int SIZE = sizeof(rates) / sizeof(double);
show1(rates, SIZE);
show2(rates, SIZE);
return 0;
}
My understanding is that arrays are really just pointers
Let's get that out of the way. No, arrays are not pointers. Arrays are a series of objects, all of the same type, contiguous in memory.
Arrays can be passed by reference, but that is not what is usually done. What is usually done, which is what you are doing, is passing a pointer to the first element of the array. Arrays can and will "decay" to a pointer to their first element upon demand. And that's what is happening when you pass rates to show1 and show2.
Inside show1 and show2, list starts out as a pointer to rates[0]. You're free to modify this pointer to point at any other double.
If you wanted to pass an array by reference, it would look like this:
void show3(double (&list)[9]) { ... }
Or the more versatile:
template<size_t SIZE>
void show3(double (&list)[SIZE]) { ... }
Note that what you can't do is pass an array by value (unless it is contained within another object). If you write a function which looks like it is taking an array by value, e.g.
void show4(double list[9]) { ... }
It is actually a pointer, and that number 9 is meaningless. Native arrays suck.
First, arrays are converted to a pointer to the first element when passed as the function argument. BTW, arrays are not pointers, as one example, sizeof(rates) in your code isn't the size of a pointer.
Second, arrays are passed by value since you are not using references.
So in the function show2, you are modifying a pointer, which is fine.
Arrays are not pointers. C++ has inherited "Array-Pointer Equivalence" from C which means that a well-known array variable can decay to a pointer, primarily for the purpose of offset math and for avoiding passing arrays by value:
int array[64];
int* a = array; // equivalent to a = &array[0];
Array's aren't pointers. If you use an array variable name in a pointer context, it will "decay" to a pointer - that is, lose the extended attributes available from an array object.
int array[64];
int* a = array;
std::cout << "array size = " << sizeof(array) << "\n";
std::cout << "a size = " << sizeof(a) << "\n";
std::cout << "(int*)(array) size = " << sizeof((int*)array)) << "\n";
"Array size" will be 256 (int is 4 bytes, 64 of them = 256 bytes), "a size" will be 4 or 8 bytes depending on 32/64 bits, and "(int*)(array)" size will be the same size as the pointer.
People often think that arrays are passed by value. This is not true: http://ideone.com/hAeH18
#include <iostream>
void bump(int arr[3]) {
for (size_t i = 0; i < 3; ++i)
arr[i]++;
}
int main() {
int array[] = { 1, 2, 3 };
bump(array);
for (size_t i = 0; i < 3; ++i)
std::cout << array[i] << "\n";
return 0;
}
This outputs "2, 3, 4" not "1, 2, 3".
This occurs because arrays decay to pointers when passed as function arguments. But to support the syntax for receiving arrays as arrays, C has to be able to treat pointers like arrays in some contexts:
void f1(int* a) { a[0]++; }
void f2(int* a) { (*a)++; }
void f3(int a[]) { a[0]++; }
void f4(int a[]) { (*a)++; }
void f5(int a[1]) { a[0]++; }
void f6(int a[1]) { (*a)++; }
All of these functions produce the same code.
In C, this originated from the fact that array information is lost at compile time. So this function:
void f(int array[])
has no way to tell how large the array it is receiving is. They wanted programmers to be conscious of this and be careful about how/if they passed size information - e.g. in the case of char arrays, instead of size, we have the nul terminator byte.
Unfortunately they didn't choose to make it obvious by diasllowing the representation that makes it look like you are receiving an array with size information intact :(
I have the following sample code. Just wanted to know if is valid to take address of a local variable in a global pointer and then modify it's contents in a sub function. Following program correctly modifies value of variable a . Can such practice cause any issues ?
#include <iostream>
#include <vector>
using namespace std;
vector<int*> va;
void func()
{
int b ;
b = 10;
int * c = va[0];
cout << "VALUE OF C=" << *c << endl;
*c = 20;
cout << "VALUE OF C=" << *c << endl;
}
int main()
{
int a;
a = 1;
va.push_back(&a);
func();
cout << "VALUE IS= " << a << endl;
return 0;
}
This is OK, as long as you don't try to dereference va[0] after a has gone out of scope. You don't, so technically this code is fine.
That said, this whole approach may not be such a good idea because it makes code very hard to maintain.
I'd say that if your program grows you could forget about a change you made in some function and get some weird errors you didn't expect.
Your code is perfectly valid as long as you call func() while being in the scope of a. However, this is not considered to be a good practice. Consider
struct HugeStruct {
int a;
};
std::vector<HugeStruct*> va;
void print_va()
{
for (size_t i = 0; i < va.size(); i++)
std::cout<<va[i].a<<' ';
std::cout<<std:endl;
}
int main()
{
for (int i = 0; i < 4; i++) {
HugeStruct hs = {i};
va.push_back(&hs);
}
print_va(); // oups ...
}
There are 2 problems in the code above.
Don't use global variables unless absolutely necessary. Global variables violate encapsulation and may cause overlay of variable names. In most cases it's much easier to pass them to functions when needed.
The vector of pointers in this code looks awful. As you can see, I forgot that pointers became invalid as soon as I left for-loop, and print_va just printed out garbage. The simple solution could be to store objects in a vector instead of pointers. But what if I don't want HugeStruct objects to be copied again and again? It can take quite a lot of time. (Suppose that instead of one int we have a vector of million integers.) One of the solutions is to allocate HugeStructs dynamically and use vector of smart pointers: std::vector<std::shared_ptr<HugeStruct>>. This way you don't have to bother about memory management and scope. Objects will be destroyed as soon as nobody will refer to them.