Dear Stackoverflow community
I am trying to understand pointers better and have come across a question:
Q: When can we use a constant pointer? Give an example with a real scenario and give some code.
I had a problem trying to find and understand where a constant pointer code be used in real-life and the code involved. I am not sure if my code meets the standard of my example. I tried the following:
My Answer:
1- Definition:
A constant pointer is a pointer that cannot change the address it is holding.
2- Example:
If you want to find a specific number stored in your phone`s contacts. Rather than duplicating your entire contacts list (and al its numbers) and then checking for that specific number. Just hold its address and check the original contacts list if the number is there.
3- Code:
int main(){
const int* number = 032 ... ;
bool found = false;
Vector<int> contactList = { 031 ... , 032 ... , 072 ... };
for(int i=0; i < contactList.size(); i++){
if( *number == contactList[i]){
valid = true;
}
}
if(valid){
cout<< "Number found"<<endl;
} else{
cout<< "Number NOT found"<<endl;
}
}
Firstly a const pointer and a pointer to const are different things:
a const pointer itself is const. It cannot be pointed to anything other than the thing it is already pointing to, be the thing it points to might be altered:
int i = 5;
int *const p1 = &i; // a const pointer
++*p1; // valid code. i is now 6
int j = 0;
p1 = &j; // error
a pointer to const itself may point to different things, but it assumes everything it points to is const, so it won't allow altering them:
int i = 5;
const int * p2 = &i; // a pointer to const
++*p2; // error
int j = 0;
p2 = &j; // valid code. p2 is now pointing to j
I assume your question is "Why would anyone use a pointer which assumes everything is const?". There may be many reasons. One of them is, when you see const int * as a function parameter, you know this function is not going to mess with your variable. It's going to stay the same after the function returns. This is essentially why we use const anyway. We could just not change variables instead, but by declaring them as const we know compiler is going to make sure our variables are not changed by mistake or misunderstanding or anything else.
Pointer to const or const pointer ?
You need to be careful about the way to define a const pointer. Because a const pointer is not a pointer to const.
static int table[10];
const int* number = table; // non const pointer to const
int * const number2 = table; // const pointer to non const
number++; // this is allowed because the pointer is not const
*number += 2; // this is NOT allowed because it's a pointer to const
number2++; // this is NOT allowed because the pointer is const
*number2 +=2; // this is allowed because the const pointer points to a non const
By the way, be careful with leading 0 since they mean octal notation:
cout << 032 <<endl; // displays 26 in decimal since 032 is octal notation
Pointers, addresses and values
Be aware of the difference between a pointer and the value pointed to. Fortunately C++ protects you in forbidding this:
const int* number = 032; // compiler error
If you want to keep a pointer to a specific value:
int myvalue=032;
const int* number = &myvalue; // ok as long as you remain in scope
Caution when pointing to vector elements
Last but not the least, if you'd be tempted to use a pointer to a vector element, be aware that the address of a vector element may change (and pointers be invalid) in certain cases, for example when the vector needs to grow.
Example of what you're trying to do
Now let's put all this together, and here a slightly modified program:
const int * number; // const to avoid accidental overwrite
int search; // value to search for
cout<<"What number are you looking for ? ";
cin>>search;
for(int i=0; i < contactList.size(); i++){
if( contactList[i] == search){ // compare values
number = &contactList[i]; // set pointer
found = true;
}
}
// if the vector is not modified, you may use the pointer.
if(found){
cout<< "Number found: "<< *number <<endl;
}
else{
cout<< "Number NOT found"<<endl;
}
Related
I have passed pointer to a pointer as a parameter to function and the goal is to make an array inside of that function. I have done that step properly and also inside of the function checked the *address and value of the array(local) as well as pointed by the pointer(op_ptr_array_) and they are the same(as desired).
But the problem is occurring while I want to dereference the provided pointer(op_ptr_array). The values are wrong while addresses are matched with the pointed array(local).
My idea is that as the address of op_ptr_array(pointer passed to the function) is equal to the local and op_ptr_array_ (array and pointer inside of the function) so using a for loop *(op_ptr_array+i) will provide me the result where i < op_size.
The approach I have taken is as follows:
#include <iostream>
void op_calculation(unsigned int* ip_ptr_array_,
unsigned int ip_size_,
unsigned int** op_ptr_array_,
unsigned int* op_size_)
{
*(op_size_) = ip_size_ + 2;
std::cout<<"op_size_ address: "<<op_size_<<std::endl;
std::cout<<"op_size_ value: "<<*(op_size_)<<std::endl;
unsigned int local[*(op_size_)];
std::cout<<"making local array to be pointed by op_ptr_array_\n";
for (unsigned int i = 0; i< *(op_size_); i++)
{
local[i]=i+1*3;
std::cout<<local[i]<<" ";
}
std::cout<<"\n";
*op_ptr_array_ = &local[0];
local[3] = 87; // for checking pointer charecter
for (unsigned int i = 0; i < *(op_size_); i++)
std::cout<<"array address: "<<&local[i]<<" ,op_ptr_array address: "<<(*op_ptr_array_)+i<<" ,val of array: "<<local[i]<<" ,val at op_ptr_array: "<<*((*op_ptr_array_)+i)<<std::endl;
// here value and addresses are same which is desired
}
int main()
{
unsigned int ip_size = 10;
unsigned int* ip_ptr_array = new unsigned int[ip_size];
unsigned int op_size;
unsigned int* op_ptr_array;
for(unsigned int i = 0; i < ip_size; i++)
{
ip_ptr_array[i] = i+2*2;
}
op_calculation(ip_ptr_array,
ip_size,
&op_ptr_array,
&op_size);
std::cout<<"Value printing after operation of op_calculation function\n";
std::cout<<"op_size: "<<op_size<<std::endl;
std::cout<<"op_ptr_array\n";
for(unsigned int i = 0; i < op_size; i++)
std::cout<<"Address: "<<(op_ptr_array+i)<<" , Value: "<<*(op_ptr_array+i)<<"\n";
/* Here only addresses are same with `local array` and
address pointed by op_ptr_array_ pointer` which you will find in op_calculation
function but values are different*/
std::cout<<"\n";
return 0;
}
Any idea where I am making the mess is highly appreciable.
Variable local is being declared as a local variable (i.e. on the stack). This falls out of scope when the function op_calculation exits, which means that the memory originally used to allocate local may be used for something else.
This can be corrected by converting local to a pointer and using new to allocate memory for the array’s contents or by declaring local as static, which will place the contents elsewhere in RAM. Keep in mind, if you use static any future calls to op_calculation will overwrite the contents of the array, even if it is still in use elsewhere. This would not be a problem if you used new, but if you use new you will need to remember to deallocate the array using delete[] when it is no longer needed.
To fully understand how pointers, values, and references work, I am making a basic C++ program that attempts to tamper with some static and dynamic arrays and understand exactly how they should be passed in.
First I generate a static array of 3 elements. I then pass it into a function that modifies all elements. I then pass it into another function with a slightly different signature, but can also alter the array's values.
Next I generate a dynamically sized array, pass it into a function by reference so that all of the values in this dynamically sized array can be altered.
The code is as follows:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
void changeIndexStaticArrayMethod1(int* stat);
void changeIndexStaticArrayMethod2(int (&stat)[3]);
void changeIndexDynamicArrayMethod1(int* dyn, int size);
int main() {
const int MAX = 3;
int arr[MAX] = { 1,2,3 };
changeIndexStaticArrayMethod1(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
cout << endl;
changeIndexStaticArrayMethod2(arr);
cout << arr[0] << endl;
cout << arr[1] << endl;
cout << arr[2] << endl;
int SIZE;
cout << "Please choose a size for the array" << endl;
cin >> SIZE;
int *ne = new int[SIZE];
//Build array
for (int i = 0; i < SIZE; i++) {
ne[i] = i;
}
changeIndexDynamicArrayMethod1(ne, SIZE);
for (int i = 0; i < SIZE; i++) {
cout << "ne[" << i << "] = " << ne[i] << endl;
}
//To hang program
cin >> SIZE;
delete[] arr;
delete[] ne;
return 0;
}
void changeIndexStaticArrayMethod1(int* stat) {
stat[0] = 10;
stat[1] = 20;
stat[2] = 30;
}
void changeIndexStaticArrayMethod2(int (&stat)[3]) {
stat[0] = 40;
stat[1] = 50;
stat[2] = 60;
}
void changeIndexDynamicArrayMethod1(int* dyn, int size) {
for (int i = 0; i < size; i++) {
dyn[i] = i * 10;
}
}
All of the above code works how I want it to, I just have a few questions as to why (some of the methods of passing arrays by reference I have found on other SO questions).
In the changeIndexStaticArrayMethod1() and changeIndexDynamicArrayMethod1() functions, why are we able to use the dereference * operator for our array as reference? My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator. I know that with arrays, it is much different than using variables, but also, why will the following not work for single int variables:
void changeStaticNumber(int* num){
num = 100;
}
Obviously the above will work if we use &num and not int* num, and obviously I don't fully understand the relationship between pointers and arrays, but I cannot figure out why when we pass an array by reference, int* staticArray is ok.
Any explanation for these problems I am having would be much appreciated. Thanks.
why are we able to use the dereference * operator for our array as reference?
The * in C means many things. It can mean the unary indirection ("contents of") operator, it can mean the binary multiplication operator and it can mean a pointer declaration. The int* stat is a pointer declaration.
Since you aren't using the * to dereference the contents of the pointer inside that function, I'm not quite sure what you are asking.
When you take the array name of your array in main(), it "decays" into a pointer to the first element. So what those function do, is to take a pointer by value. If you dereference the pointer by typing *stat = something; you access the actual array in main.
Should you do something weird like changing the pointer itself, for example stat++;, then it will not affect the address used in main. You passed the pointer itself by value, so the pointer is a local copy.
My knee jerk reaction is seeing that as practically passing the array in by values since it is the dereference operator.
You can't really pass arrays by value in C or C++, without resorting to dirty tricks (storing them inside structs or classes). For example, had your function been written as void changeIndexStaticArrayMethod1(int stat[3]) it would still give you a pointer to the first element. It will not pass an array by value, as the syntax might trick you into believing.
why will the following not work for single int variables:
void changeStaticNumber(int* num){ num = 100; }
Because num is the pointer itself, not its contents. In order to write code like that, you could pass the variable by reference int& num. Behind the lines this is really the same thing as passing a pointer, just with simplified syntax.
To understand the relation between pointers and arrays better, start by reading this whole chapter: http://c-faq.com/aryptr/index.html (C and C++ are identical when it comes to pointers).
Let me see if I can take a stab at this.
Pointers are simply address holders. Once you do int * ptr = myarray; --- what you are in tern doing is storing the address of the pointer my array into ptr --- array names are actually pointers to the first memory location in the array. You can use pointer arithmetic to get at everything else for example myarray +1 will point you to the next location or myarray[1].
Passing by value is not very useful when you need to modify your array. Passing in by reference is essentially making a pointer to the array and passing that. Since arrays like vectors are contiguous blocks of memory you can index through them rather easily.
As far as your example goes void changeStaticNumber(int* num){ num = 100; } will not work because what you are attempting to do is store 100 into the pointer's address. If you deference num and make it void changeStaticNumber(int* num){ *num = 100; } it will work because you are actually going one step further and accessing the data that num is pointing to. When you use &num it is essentially the same thing - & just gives you the address of something.
For example if you want to point a pointer to an int what you would do is
int num = 5;
int *ptr = #
at this point in time ptr has the same address in num. To print out the data in num or that ptr is pointing to you need to dereference or go one step further as I like to tell myself and dereference to so cout << *ptr;
In both changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 you are not passing an array there is no pass by reference (which only happens if the parameter type is a reference type -- i.e. with &). The parameter has type int * (pointer to int). You are passing a pointer to int by value. There is no "dereference operator" in either function.
ne is already an int *, so passing it is nothing special. arr is an int [3], an array, not a pointer. In C, when an array-of-T is used in a context that expects a pointer-to-T, it is implicitly converted (without you needing to do anything) to a pointer to its first element. So when you do, changeIndexStaticArrayMethod1(arr), the compiler gets a pointer to the first element of arr, and passes that to the function.
The [] operator works on pointers. a[i] is always guaranteed to be the same as *(a + i). Inside both the changeIndexStaticArrayMethod1 and changeIndexDynamicArrayMethod1 functions, [] is used to access subsequent elements using a pointer to the first element.
I have a method which fills the array with integers:
void fill(int* a[], int dim1, int dim2)
{
int intinArray = 0;
for(int i=0;i<dim1;i++)
{
for(int j=0;j<dim2;j++)
{
cin >> intinArray;
a[i][j] = intinArray;
}
}
}
If I declare array in method main() like this:
int** tab;
fill(tab,3,3);
It crashes when I put the first integer in cin. Why? If there's a problem with this line:
a[i][j] = intinArray;
how should I change it?
The fundamental thing wrong with your code is that you declared pointers, but nowhere do you initialize the pointers to point somewhere. You treat the pointer as if it is a regular old 2 dimensional array of integer. So if it's as easy as that, why use pointers?
Given that this is a fundamental in pointer usage and you plainly aren't doing that, the solution is to review working code that uses pointer.
int main()
{
int *p; // uninitialized -- points to who-knows-where
*p = 10; // this is undefined behavior and may crash
}
Take that code and understand why it also may crash. That pointer points to "we don't know", and then you're assigning 10 to a location that is unknown to you, me, and everyone else reading this answer. See the problem? To fix it, you have to initialize the pointer to point somewhere valid, then you can dereference it and assign to it without error.
int main()
{
int *p; // uninitialized -- points to who-knows-where
int x = 20;
p = &x; // this is now ok, since p points to x
*p = 20; // now x changes to 20
}
Your problem is in this code
int** tab; // <- this one
fill(tab,3,3);
You declared a pointer, and are using it under the assumption that it is pointing to allocated memory. (I guess a source of confusion is that with C++ objects this isn't really the case)
A pointer is a pointer - it points to a location in memory. There's no guarantee that the value it points to is valid unless you explicitly make sure it is yourself.
Read PaulMcKenzie's answer for more about pointers.
Try
int tab[x][y] = {{0}};
fill(tab,3,3);
where x and y define your 2D array's width and height. You're going to have to handle bounds checking for your application.
Note that changing {{0}} to a non zero number will not initialize everything to that number.
A very general question: I was wondering why we use pointer to pointer?
A pointer to pointer will hold the address of a pointer which in turn will point to another pointer. But, this could be achieved even by using a single pointer.
Consider the following example:
{
int number = 10;
int *a = NULL;
a = &number;
int *b = a;
int *pointer1 = NULL;
pointer1 = b; //pointer1 points to the address of number which has value 10
int **pointer2 = NULL;
pointer2 = &b; //pointer2 points to the address of b which in turn points to the address of number which has value 10. Why **pointer2??
return 0;
}
I think you answered your own question, the code is correct, what you commented isn't.
int number = 10; is the value
int *pointer1 = b; points to the address where int number is kept
int **pointer2 = &b; points to the address where address of int number is kept
Do you see the pattern here??
address = * (single indirection)
address of address = ** (double indirection)
The following expressions are true:
*pointer2 == b
**pointer2 == 10
The following is not!
*pointer2 == 10
Pointer to pointer can be useful when you want to change to what a pointer points to outside of a function. For example
void func(int** ptr)
{
*ptr = new int;
**ptr = 1337;
}
int main()
{
int* p = NULL;
func(&p);
std::cout << *p << std::endl; // writes 1337 to console
delete p;
}
A stupid example to show what can be achieved :) With just a pointer this can not be done.
First of all, a pointer doesn't point to a value. It point to a memory location (that is it contains a memory address) which in turn contains a value. So when you write
pointer1 = b;
pointer1 points to the same memory location as b which is the variable number. Now after that is you execute
pointer2 = &b;
Then pointer2 point to the memory location of b which doesn't contains 10 but the address of the variable number
Your assumption is incorrect. pointer2 does not point to the value 10, but to the (address of the) pointer b. Dereferencing pointer2 with the * operator produces an int *, not an int.
You need pointers to pointers for the same reasons you need pointers in the first place: to implement pass-by-reference parameters in function calls, to effect sharing of data between data structures, and so on.
In c such construction made sense, with bigger data structures. The OOP in C, because of lack of possibility to implement methods withing structures, the methods had c++ this parameter passed explicitly. Also some structures were defined by a pointer to one specially selected element, which was held in the scope global to the methods.
So when you wanted to pass whole stucture, E.g. a tree, and needed to change the root, or 1st element of a list, you passes a pointer-to-a-pointer to this special root/head element, so you could change it.
Note: This is c-style implementation using c++ syntax for convienience.
void add_element_to_list(List** list, Data element){
Data new_el = new Data(element); // this would be malloc and struct copy
*list = new_el; //move the address of list, so it begins at new element
}
In c++ there is reference mechanismm and you generally you can implement nearly anything with it. It basically makes usage of pointers at all obsolete it c++, at least in many, many cases. You also design objects and work on them, and everything is hidden under the hood those two.
There was also a nice question lately "Why do we use pointers in c++?" or something like that.
A simple example is an implementation of a matrix (it's an example, it's not the best way to implement matrices in C++).
int nrows = 10;
int ncols = 15;
double** M = new double*[nrows];
for(unsigned long int i = 0; i < nrows; ++i)
M[i] = new double[ncols];
M[3][7] = 3.1416;
You'll rarely see this construct in normal C++ code, since C++ has references. It's useful in C for "passing by reference:"
int allocate_something(void **p)
{
*p = malloc(whatever);
if (*p)
return 1;
else
return 0;
}
The equivalent C++ code would use void *&p for the parameter.
Still, you could imagine e.g. a resource monitor like this:
struct Resource;
struct Holder
{
Resource *res;
};
struct Monitor
{
Resource **res;
void monitor(const Holder &h) { res = &h.res; }
Resource& getResource() const { return **res; }
}
Yes, it's contrived, but the idea's there - it will keep a pointer to the pointer stored in a holder, and correctly return that resource even when the holder's res pointer changes.
Of course, it's a dangling dereference waiting to happen - normally, you'd avoid code like this.
This question already has answers here:
Function does not change passed pointer C++
(4 answers)
Closed 8 years ago.
so right now i am trying to do some nift code for a little game i am making and I've run into something that has been bothering me for a while about pointers.
but first things first, i am trying to have a function take in a void* and give that void* a value, but it seems to not actually stay beyond the function like i'm used to. so...
void ItemGen(void* Holder){
Item* NewItem
NewItem = new Item*
NewItem->Init();
Holder = NewItem;
}
it's not actually making "items" but various kinds of items that inherit from a item, this is just me making it simpler.
Holder gets changed but never make it outside the function, how should i change this, so that it does.
on top of that, i am sort of confused about a certain occurrence that can happen and i just want to know what happens when you do these. or really the difference between them
void *p1;
void *p2;
&p1 = &p2;
p1 = p2;
*p1 = *p2;
oh and is there a way to do a XOR operation on pointers so i can swap them with out a holding pointer.
i feel like i asked very stupid questions, but are confusing simply because they're void *'s.
Pointers are variables like any other, and as such are passed by value to functions. You've simply assigned a new value to the parameter copy of your pointer.
If you want to change a variable you pass to a function you must pass by reference or by pointer. Preferably the former.
void ItemGen(void *& Holder);
BTW, that's a horrible naming convention.
I am answering this point "Holder gets changed but never make it outside the function, how should i change this, so that it does."
void ItemGen(Item** Holder){
Item* NewItem
NewItem = new Item*
NewItem->Init();
*Holder = NewItem;
}
void someotherfunc() {
Holder * holder=0;
ItemGen(&holder)
if(holder!=0) {
holder->dosomething()
}
}
"void" simply means "nothing". A "void*" pointer points to nothing in particular. It's a way of saying "I don't know what kind of thing this pointer points to"; a void* pointer is a catch all that can receive any kind of pointer, but if you want to go from a void* pointer to any other kind, you have to explicitly cast it.
As to your first problem:
If you lived at "1234 Pointer Street", there is nothing magical about the number "1234", it's just a number. It only tells you anything when you treat it as a "pointer" - a house number. It "points" to a house on a particular street.
In the case of a computer, the street is memory.
int a = 0;
int* b = 0;
the variables "a" and "b" both contain the numeric value "0".
b = b + 1;
See? perfectly valid. So
void foo(int a, int* b)
{
a = a + 1;
b = b + 1;
}
void bar()
{
int x = 0;
int* y = 0;
foo(x, y);
// 'x' and 'y' are still zero here, they have to be, or you couldn't do
foo(0, 0);
}
Pointers to have some distinguishing features from regular variables.
int a = 0;
int* b = 0;
a = a + 1; // now a = 1
b = b + 1; // now b = b + sizeof(int) => 4.
What pointers do best is provide values for C/C++'s "dereference" operators.
a = *(b);
Going back to the streets example, if we assigned b our "1234 Pointer Street" address, it would be:
b = 1234;
What if we wanted to deliver something there?
*b
This means: The contents of the address that b describes.
Lets go back to the definition
int* b;
This says: "b is the address of an integer". How do we get the address of a specific integer?
// imagine a set of mailboxes.
int box1, box2, box3, box4, box5;
// lets put something interesting into box 3.
box3 = 5;
// now let's address somethign to box3.
// "&" is the "address of" operator.
int* pointer = &box3;
// now lets put something more interesting in pointer.
pointer = 10;
// whoops - that was wrong, we just changed the ADDRESS to some random numeric value.
// what we mean't was:
*pointer = 10;
printf("box 3 contains %d\n", box3);
// answer? 10, not 5.
After setting "pointer = &box3" we populated "pointer" with the location of box3's storage in memory, so when we wrote to that address using "*pointer = 10" we wrote to the storage address of box3.
You asked about
void *p1;
void *p2;
&p1 = &p2;
p1 = p2;
*p1 = *p2;
"&p1 = &p2" says "the address of p1 is the address of p2" and isn't legal, it wouldn't compile.
"p1 = p2" is legal, but it says "assign the same address as p2 to p1"
"*p1 = *p2" is illegal because you are using void pointers, which point to void, besides, you've just made p1 and p2 be equal to each other so it would be a null operation.
To fix your initial problem, you would need to provide a way for the caller to receive the new value you are creating.
Option 1: Accept a pointer-to-pointer
This is the very old-school C way to do it, but your code doesn't look very C++ so far so I'll list it first.
void ItemGen(void** Holder)
{
Item* NewItem = new Item;
NewItem->Init(); // why doesn't the constructor do this?
// ** means pointer to storage that is itself also a pointer,
// so if we dereference it once we will be refering to the inner pointer.
*Holder = NewItem;
}
Option 2: Return a pointer
void* ItemGen() // Why isn't this "Item*"?
{
Item* NewItem = new Item;
NewItem->Init();
return NewItem;
}
Option 3: Take a reference
void ItemGen(Item*& Holder)
{
Holder = new Item;
Holder->Init();
}
This says "Holder is a reference to a pointer to storage of type Item". It's exactly like a "Item*" pointer except instead of creating a temporary local copy of the value passed in, it's an alias for the value that was passed in.
If you absolutely have to throw away the type information of your pointer:
void ItemGen(void*& Holder)
{
Item* NewItem = new Item;
NewItem->Init();
Holder = NewItem;
}
At the level you appear to be with C++ so far, I would guess that your use of void* pointers is probably misguided.