Pointer Variable to Locate the zero in the array - c++

I am trying to make a code that tries to scan over an array for '0' using a pointer variable and then setting the address to that of the space in the array that has '0' in it. Unfortunately, my program is returning 10 as the value and 0 as an index. I would really appreciate any input to help me, and I'm trying to do this without changing main, so I dont think the following code is possible.
int* zerofinder(int array[], int q)
{
int* p = null; /// default value if there isn't a 0 in the array at
all
for (int k = q - 1; k >= 0; k--)
{
if (arr[k] == 0) // found an element whose value is 0
{
p = arr[k]; // change the value of p
break; // stop looping and return
}
}
return p;
}
Instead I think I have to use
void zerofinder(int array[], int x, int* p); function to change the pointer?

You pass the pointer by value.
Then you change where the pointer points to but that only modifies the local copy. It does not change the value of the pointer in the calling function.
You can resolve the problem using one of the following two approaches.
Pass the pointer by reference.
void findLastZero(int arr[], int n, int*& p);
Return the pointer from the function.
int* findLastZero(int arr[], int n);
This will change how you call the function. Instead of using:
int* ptr;
ptr = &nums[0];
findLastZero(nums, 6, ptr);
you can use:
int* ptr = findLastZero(nums, 6);

The problem is that you don't return the value you want from the function
int* findLastZero(int arr[], int n)
{
int* p = nullptr; /// default value if there isn't a 0 in the array at all
for (int k = n - 1; k >= 0; k--)
{
if (arr[k] == 0) // found an element whose value is 0
{
p = &arr[k]; // change the value of p
break; // stop looping and return
}
}
return p;
}
and
ptr = findLastZero(nums, 6);
Sometimes newbies think that pointers are something special, but pointers are values too, and obey the usual C++ rules about pass-by-value. If you pass a pointer to a function then changing the value of that pointer inside the function has no effect on the value outside the function, just like any other type.

This looks like a homework / test / quiz.
The answer to this quiz is: this can't be done without changing the main function.
Why?
As others have already told you, you need to change the findLastZero signature, either changing the p parameter type as int*& or int**, or return an int* from the function.
If you don't change the findLastZero signature (and the main), the findLastZero function has no way to change the outer ptr variable.

Related

Access an element of a vector given the vector's pointer

I am trying to create a sorting function with the parameters being a pointer of a list and I am trying to access an element of the given list. Hopefully this code speaks for the problem better than I can:
void bubbleSort(std::vector<int> *L) {
unsigned int i = 0; int temp;
while(isSorted(*L)) {
if(i==L->size()-1) {
i = 0;
}
if(i<L[i]/*<-ERROR here.*/) {
temp = L[i+1]; // ERROR HERE
L[i+1] = L[i]; // ERROR HERE
L[i] = temp; // ERROR HERE
}
}
}
You don't need to painfully dereference every individual use of L (and indeed doing so is error-prone, as you've demonstrated by missing one in your answer).
Instead, just write:
void bubbleSort(std::vector<int> *Lptr) {
auto &L = *Lptr;
and keep the rest of the code the same.
NB. It would be even better to change the function itself, to
void bubbleSort(std::vector<int> &L) {
as it should have been written in the first place, but I'm assuming there's some artificial reason you can't do that.
The function accepts a pointer to an object of type std::vector<int>.
void bubbleSort(std::vector<int> *L) {
To access the original vector using the pointer, you can write either *L or L[0]. That is, both expressions yield an lvalue reference of type std::vector<int> & to the vector.
To get the i-th element of the vector using the subscript operator through the pointer, you can write either (*L)[i] or L[0][i],
However, in this if statement:
if(i<L[i]/*<-ERROR here.*/) {
You are trying to compare the variable i of type unsigned int to the object L[i] of type std::vector<int>. When i is not equal to 0, this yields a non-existent object of the vector type.
It seems you mean something like the following instead:
if ( (*L)[i] < (*L)[i+1] ) {
or:
if ( L[0][i] < L[0][i+1] ) {
or, vice versa:
if ( L[0][i+1] < L[0][i] ) {
Depending on whether the vector is sorted in ascending or descending order.
Pay attention to the fact that there is no sense in declaring the parameter as a pointer to a std::vector<int>. The function would be much clearer and readable if it accepted the vector by reference instead:
void bubbleSort(std::vector<int> &L) {
In this case, the if statement would look like this:
if ( L[i] < L[i+1] ) {
Although I prefer to change the source code as other answer. But, for this question, you can use ->at() function to access the element in a vector pointer.
if(i<L->at(i)) {
temp = L->at(i+1);
L->at(i+1) = L->at(i);
L->at(i) = temp;
}

C++ Swapping Values By Reference

I came across a C++ code snippet in my exams which was quite confusing (at least for me). I tried to analyze it but there is something that I am unable to understand. The code is written below:
#include <iostream>
using namespace std;
int* doMagic(int *p, int *q)
{
int* t = new int();
t = p;
p = q;
q = t;
return t;
}
int main()
{
int p = 5, q = 10;
int *t = NULL;
t = doMagic(&p, &q);
cout<<"p = "<<p<<endl;
cout<<"q = "<<q<<endl;
cout<<"t = "<<*t<<endl;
return 0;
}
The output is:
p = 5
q = 10
t = 5
Now my question is that when the values were passed by reference to doMagic function why weren't the values swapped in it.
Help will be highly appreciated.
Thanks.
The variables p and p in doMagic are local to the function. Any changes made to those variables are made locally in the function. They don't change anything in the calling function.
You can rename those variables to x and y without changing the function's behavior. That will also be a reminder that the names in main and the name in doMagic are separate and independent.
You can swap the values in doMagic by swapping the values of the objects the pointers point to:
void doMagic(int *p, int *q)
{
int t = *p;
*p = *q;
*q = t;
}
although it is idiomatically better C++ to use references
void doMagic(int& p, int& q)
{
int t = p;
p = q;
q = t;
}
Then, the function can be called from main as:
doMagic(p, q);
Having said that, if you don't intend to do anything more in the function, you should use std::swap instead. There is nothing to gain by defining a function in user space that duplicates the functionality of a standard library function.
In this code nothing gets passed by reference.
Some pointer values (&p, &q) get passed by value.
Because they were passed by value, they were stored into new variables in doMagic called p and q. The new variables were then swapped. The value &p was returned and stored in main's variable t.
Also, some memory was leaked, because an int was created with new and was never destroyed with delete.

Why can't we pass int array[] to hoo(int* &p)?

In my understanding array in int array[]={1,2,3,4,5} is just a pointer to the first element of array. It means that array can be assigned to a pointer ptr of type int*.
Parameter int* &p in hoo will pass the argument by reference. It means we can change the passed argument to point to another value from within the hoo.
void hoo(int* &p, int n)
{
for (int i = 0; i < n; i++)
cout << p[i] << endl;
}
int main()
{
int array[] = { 1,2,3,4,5 };
// I can do this
int* ptr = array;
hoo(ptr, 5);
// but not this.
//hoo(array, 5);
}
Question
Why can't we pass int array to hoo without ptr ?
In my understanding array in int array[]={1,2,3,4,5} is just a pointer to the first element of array.
This is not correct. Arrays are arrays and pointers are pointers. They are distinct types with distinct properties. They are often confused because an array has the property that it will eagerly decay to a pointer to its first element.
hoo(array, 5); tries to convert array to an int* but the result of that conversion is an rvalue and can't be bound to a non-const reference. If, for example, you changed hoo to take a const reference it will compile fine :
void hoo(int* const &p, int n) { }
int main()
{
int array[] = { 1,2,3,4,5 };
hoo(array, 5);
}
In that case, you cannot change what p points to, making the use of a reference pointless.
When a function takes an int* & parameter, that is, a (non-move) reference to a pointer-to-an-int - then there needs to be a bona fide pointer variable to which that reference is referring. It can't be a temporary pointer value. Thus you can't do:
int x;
hoo(&x, 123);
because there's no pointer variable to refer to - just the temporary. It's essentially the same thing with your int[5]. There isn't actually an int* variable anywhere - there are just 5 ints. When you pass array to hoo(), what C++ does with that identifier is an array-to-pointer decay: It actually passes &(array[0]). So just like in the previous case, that won't compile.
The other answers already explain the problem. I want to suggest a change of coding practice.
Use of void hoo(int* &p, int n) as function declaration is very very old style. Using templates, you can let the compiler deduce the size and get a reference to the array, which obviates the need for using a pointer.
template <size_t N>
void hoo( int (&p)[N]) // The argument is a reference to an array of N elements.
{
for (int i = 0; i < N; i++)
cout << p[i] << endl;
}
The call to the function becomes natural.
int array[] = { 1,2,3,4,5 };
hoo(array);
If your function needs to be able to support dynamically allocated arrays as well, you can overload the function as follows.
void hoo(int* p, size_t N)
{
for (int i = 0; i < N; i++)
cout << p[i] << endl;
}
template <size_t N>
void hoo( int (&p)[N]) // The argument is a reference to an array of N elements.
{
hoo(p, N);
}

Increment pointer returned by function

Hey I was experimenting a bit with C/C++ and pointers
while reading stuff here
I made myself a function to return a pointer to the int at some place in a global array.
int vals[] = { 5, 1, 45 };
int * setValue(int k) {
return &vals[k];
}
However I was able to do this
int* j = setValue(0);
j++;
*j = 7;
to manipulate the array
but that:
*(++setValue(0)) = 42;
din't work.
Notice however *setValue(0) = 42; works
From what I understand I call the function and get some pointer I increment it to make it point to the 2nd element in my array. Lastly I deference the pointer and assign a new value to the integer it pointed to.
I find C++ pointers and references can be somewhat confusing but maybe someone can explain me this behavior.
EDIT:
This question is NOT a duplicate of Increment, preincrement and postincrement
because it is not about pre- vs. post-increment but rather about increment on pointers that are the return of a function.
EDIT2:
Tweaking the function
int ** setValue(int k) {
int* x = &vals[k];
return &x;
}
You can use
*(++(*setValue(1))) = 42;
You can't call a unary operator (++) on something that is not a variable. setValue(0) is treated as a value.
So,
*(setValue(0)++) = 42;
should be
*(setValue(0) + 1) = 42;

C++ pointer array argument

I have the following code:
void getPossibilities(int *rating[200][3]){
// do something
}
int main ()
{
int rating[200][3];
getPossibilities(&rating);
}
this throws following error message:
error: cannot convert int ()[200][3] to int ()[3] for argument 1 to void getPossibilities(int (*)[3])
The function signature should be this:
void getPossibilities(int (*rating)[3]);
and pass argument as:
getPossibilities(rating);
The variable rating is a two dimentional array of form T[M][N] which can decay into a type which is of form T(*)[N]. So I think that is all you want.
As in the above solution the array decays, losing the size of one dimension (in the function you only know N reliably, you just loss M due to the array-decay), so you've to change the signature of the function to avoid decaying of the array:
void getPossibilities(int (&rating)[200][3]) //note : &, 200, 3
{
//your code
}
//pass argument as before
getPossibilities(rating); //same as above
Better yet is to use template as:
template<size_t M, size_t N>
void getPossibilities(int (&rating)[M][N])
{
//you can use M and N here
//for example
for(size_t i = 0 ; i < M ; ++i)
{
for(size_t j = 0 ; j < N ; ++j)
{
//use rating[i][j]
}
}
}
To use this function, you've to pass the argument as before:
getPossibilities(rating); //same as before!
When passing an array of N-dimensions to a function, the 0th dimension is always ignored. That's why a[N] decays to *p. In the same way, a[N][M] decays to (*p)[M].
Here, (*p)[M] is a pointer to an array of M elements.
int a1[N][M], a2[M];
int (*p)[M];
p = a1; // array a1[N][M] decays to a pointer
p = &a2; // p is a pointer to int[M]
So your function signature should be:
void getPossibilities(int (*rating)[3]);
Now since you are using, C++, it's worth taking advantage of its facility where you can pass an array by reference. So preferred way is:
void getPossibilities(int (&rating)[200][3]);
There is a difference between int (*x)[200][3] and int *x[200][3]