C++ for_each() and the function pointer - c++

I am try to make the myFunction give me a sum of the values in the array, but I know I can not use a return value, and when I run my program with the code as so all I get is a print out of the values and no sum why is that?
void myFunction (int i) {
int total = 0;
total += i;
cout << total;
}
int main() {
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for_each( array, array+10, myFunction);
return 0;
}

You really need a functor to store state between iterations:
struct Sum
{
Sum(int& v): value(v) {}
void operator()(int data) const { value += data;}
int& value;
};
int main()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int total = 0;
std::for_each( array, array+10, Sum(total));
std::cout << total << std::endl;
}

When you declare a variable (i.e. int total) it exists for the duration of its scope (usually equivalent to the nearest surrounding pair of { and }. So, in your function myFunction, total ceases to exist when the function returns. It returns once per call--once per element in your array, that is. In order to actually sum its values (or otherwise preserve a variable beyond the end of myFunction, you must give it a broader scope.
There are two relevant ways to do this. One is a "good" way, and one is an "easier-but-badly-styled" way. The good way involves a functor or context object--#Martin has already posted an example. The "bad" way is marking int total as static. It'll work the first time you use it, if your code is single-threaded... and then never again. If somebody suggests it... don't do it. :)

total is a variable with automatic storage duration. Every time myFunction() is called, a new total is created and initialized to 0. You could:
give total static storage duration (with the static keyword), but you won't be able to assign its value to anything, because it is still local scope. A bad idea if you want to reuse this function, anyhow.
make total a global variable. Also a bad idea if you want to reuse this function
make a "functor", as described in Martin York's answer. This is the most reusable implementation
But, my chosen solution is "you're asking the wrong question" and you should be using std::accumulate():
#include <iostream>
#include <numeric>
int main() {
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int total = std::accumulate(array, array+10, 0);
std::cout << total << '\n';
return 0;
}

Your total is local at each function call. It's initialized with 0 at every iteration. You could just declare it global (or pack into a parameter, etc.)

myFunction is being called each time and total is local to the function... try marking total as static instead:
static int total = 0

You need to make the total persistent across function calls. You also need to access the result separately from adding the intermediate results to it, which rules out (at least straightforward use of) a function at all -- you really need a class instead.

The total is a local variable. It will be destroyed once the myFunction finished processing one data.
The typical way to have a state is to make myFunction a function object (a struct that overloads the () operator).
The dirty way is to make total a global variable.
In your case I'd recommend you use the accumulate function instead (assuming that cout << total is just for debugging).

You reset the value of 'total' to 0 each time you call the function.
Declare it 'static'
void myFunction (int i) {
static int total = 0;
total += i;
cout << total;
}
EDIT:
Alternatively, if you want to access the value of 'total' later, you will need to either use a global variable (of some kind! Could be in a class or functor! don't flame me!), or just use a for loop, and pass it in as a pointer (i.e., not use for_each):
void myFunction (int i, int * p_total) {
//No initialization
*p_total += i;
cout << *p_total;
}
int main() {
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int total = 0;
for(int i = 0; i < 10, i++)
myFunction(array[i], &total);
//total is now 55
return 0;
}
Note: I'm a C programmer trying to learn C++. This is how I would do it (which is very C-like), it might not be the standard C++ way.

Related

I am getting this error while sorting 0,1 and 2 in array - Runtime Error Time Limit Exceeded Your program took more time than expected

class Solution
{
public:
void sort012(int a[], int n)
{
// code here
int low = 0;
int high = n-1;
int mid = 0;
while(mid<high)
{
int high = n-1;
if(a[mid]==0 && mid<=high)
{ swap(a[mid++],a[low++]);
}
else if(a[mid]==2 && mid<=high)
{ swap(a[mid],a[high--]);
}
else if(a[mid]==1 && mid<=high)
{
mid++;
}
}
}
};
Problem number one is you are redefining the int high = n - 1 inside of the while loop, at each iteration it's reset to this value, so high-- has no effect, and you're getting inside an infinite loop.
Problem number two is that potentially if you pass an array a which has a single value that is not a 0, 1 or 2, you are 100% getting into an infinite loop as well.
Check out this compiler explorer link for an interactive demo: https://godbolt.org/z/EbKPqrxz4
For what it's worth, you program looks like bad C instead of being C++. Non exhaustive list of issues:
The sort012 is an instance method on a class while it doesn't use the instance state. It's probably better as a free function, or at worse a static method on that class.
You're using C arrays.
As a result, you're also not using the algorithms provided by the STL.
I'm assuming this is a kind of coding exercise, but anyways, for the sake of completeness you could achieve the same thing (and more, it'd work with several containers, and regardless of your values/types) with fewer lines of code with this (Compiler Explorer):
#include <fmt/format.h>
#include <algorithm>
#include <array>
int main() {
std::array<int, 10> a{1, 2, 0, 1, 2, 1, 2, 1, 0, 2};
// Could also be a vector: `std::vector<int> a{1, 2, 0, 1, 2, 1, 2, 1, 0, 2};`
std::sort(a.begin(), a.end());
fmt::print("sorted a=");
for (auto x: a) {
fmt::print("{}, ", x);
}
}

How to iterate over a pointer to an array (int*) when size is not known?

I was looking through some coding problems and I've come across a problem where the input array is given as "int*" instead of vector.
This made me question how to iterate through this array if we didn't know the size:
vector<int> cellCompete(int* states, int days)
{
// my try:
for (; *states; states++ ) {
cout << *(states) << " ";
}
vector<int> testArray;
return testArray;
}
As you can see i've tried a simple way to iterate over the array, trying to check if the pointer would return nullptr at a point.
Example:
[1, 0, 0, 0, 0, 1, 0, 0] returned "1" as output
[1, 1, 1, 0, 1, 1, 1, 1] returned "1 1 1" as output.
However, this approach worked in the following example:
#include <iostream>
using namespace std;
int main () {
// an array with 5 elements.
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
p = balance;
for (; *p; p++ ) {
cout << *(p) << endl;
}
return 0;
}
This is the question https://www.geeksforgeeks.org/active-inactive-cells-k-days/ but I cannot share the link for where I've come across the question because it is confidential. In the version that I had to solve, the function input was "int*" instead of other options.
Extras:
On the same website, my approach worked for another question with similar input:
int generalizedGCD(int num, int* arr)
{
// WRITE YOUR CODE HERE
for (; *arr; arr++ ) {
cout << *(arr) << " ";
}
return 1;
}
where the input examples were:
[2, 3, 4, 5, 7] and [2, 4, 6, 8, 10]
Is there a more reliable way to iterate through a pointer to an array when we do not know the size of the array?
None of the sources I've found online give a way to iterate without knowing the size.
I wanted to express that this question did indicate the size of the array but it just made me think if there is a way to iterate without given size.
No, there isn't.
You either need to have some kind of a terminating character, like in null-terminated strings or explicitly provide the size.
Besides your approach does not work and is not safe.
*states will not tell you if your pointer is nullptr. operator* is dereferencing and taking value of the object referenced by the pointer. That is why your cycle stops once it hits a 0 value in your array. If you do not have any zeroes in the array, the cycle will go on until going out of the allocated space for you array, and you will have an unaddressable access resulting in undefined behavior, because you will be accessing memory, which could be used for something else, or even worse could be read-only or outside process's address space, causing a crash.
To take the actual value of the pointer (the address), you need to check states instead of *states, but it will not be nullptr. The value of the variable states is just some number(which is equal to the address of the memory where the array is written).

FIXED Trying fix broken code on reversing an array

So I got this code sample that needs fixing. From what I can gather it takes an array, reverses it and then counts all the elements within it. Here is the code.
//-------------------------------------------------------------------
void ReverseTheArray( const short *pArrayStart, const int nArrayByteLength )
{
const short *pArrayEnd = (pArrayStart + nArrayByteLength);
while(pArrayStart != pArrayEnd)
{
short tmp = *pArrayStart;
*pArrayStart = *pArrayEnd;
*pArrayEnd = tmp;
pArrayStart++;
pArrayEnd--;
}
}
//-------------------------------------------------------------------
int CountTheArrayContents( const short *pArrayStart, int nNumEntries )
{
assert(nNumEntries-- > 0);
int nCount = 0;
for(unsigned uArrayIndex = nNumEntries; uArrayIndex >= 0; uArrayIndex--)
{
nCount += pArrayStart[uArrayIndex];
}
return nCount;
}
const short g_nSomeNumbers[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
//-------------------------------------------------------------------
int main()
{
short *pDataArray = new short[10];
memcpy(pDataArray, g_nSomeNumbers, sizeof(g_nSomeNumbers));
ReverseTheArray(pDataArray, 10*sizeof(short));
int nCount = CountTheArrayContents(pDataArray, 10);
printf("Sum total is %0.02f\n", nCount);
return 0;
}
I have ideas of what the problems are but can't seem to figure out a simple solution to the problem, one that doesn't require rewriting the entire code. If anyone can read this and see how the errors can be fixed it would be much appreciated.
I'm going to mention some things that I think are causing problems.
All the parameters and the pArrayEnd variable in the ReversTheArray() function are all const but are trying to be changed within the while loop, which is throwing an error. Should the const's be removed? Is there a reason const's would be used for this?
If the const's are remove a runtime error happens when trying to run the for loop in the CountTheArrayContents() function expressing an unhandled exception and saying "Access violation reading location 0x003DFFFE". Drawing a complete blank on that one.
Again any help on the code would be very much appreciated and I couldn't thank you guys enough.
PS. This is a challenge to create a reverse and accumulate function so I'm looking for a fix for the code and not a removal of the two functions. Thank you
PSS. Thanks to everyone who answered. I'm glad I did this (this being the first problem that I've posted about myself) and you've all been a huge help. I've got to say I've learnt alot.
Adding the actual length in bytes will add too many because pointer arithmetic is defined in terms of units of the size of the type pointed to. That is, pArrayEnd becomes &pDataArray[10 * sizeof(short)] instead of &pDataArray[10]. You don't need to multiply by sizeof(short) when calling the reversal function. Alternatively, you can divide nArrayByteLength by sizeof(short) when calculating the initial value of pArrayEnd.
The second issue is the fact that you only have 10 elements (0..9) allocated, meaning &pDataArray[10] would be one element beyond the array. The reversal function then tries to assign data to this unallocated area of memory, which can cause problems. The function should initialize pArrayEnd as shown, but immediately after, it should decrement pArrayEnd by 1. This way you won't be assigning to memory that might not belong to you. Beware of pArrayStart == pArrayEnd before you decrement pArrayEnd. An alternative test would be to ensure nArrayByteLength != 0.
Another problem is if the array has an even number of elements, and you try to do a reversal. If it does have an even number (like 10), pArrayStart will point to pDataArray[4], pArrayEnd will point to pDataArray[5], and after the data is assigned, pArrayStart++ will make pArrayStart point to pDataArray[5] and pArrayEnd-- point to pDataArray[4]. Then (6,3), (7,2), (8,1), (9,0), ... In other words, pArrayStart will never be equal to pArrayEnd in such a case. Instead, you should ensure that pArrayStart < pArrayEnd.
Hope this helps!
Also, any reason for not using std:: reverse? Just wondering.
Edit
The accumulation function can be rewritten as the following, which will avoid the issue with the assert macro while doing the same thing:
int CountTheArrayContents( const short *pArrayStart, int nNumEntries )
{
int count = 0;
assert(nNumEntries);
while (nNumEntries--)
count += pArrayStart[nNumEntries];
return count;
}
Hopefully count doesn't overflow.
If all you're trying to do is reverse the contents of the array and accumulate the result, std::reverse and std::accumulate will do the trick (per the suggestion by #chris). Here's an example, which maintains the dynamically allocated short*. A better solution would use std::vector or std::array.
#include <algorithm>
#include <numeric>
#include <stdio.h>
#include <memory.h>
const short g_nSomeNumbers[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
int main()
{
short *pDataArray = new short[10];
memcpy(pDataArray, g_nSomeNumbers, sizeof(g_nSomeNumbers));
std::reverse(pDataArray, pDataArray+10);
int nCount = std::accumulate(pDataArray, pDataArray+10, 0);
for( size_t i=0; i<10; ++i )
printf("%d ", pDataArray[i]);
printf("\n");
printf("Sum total is %d\n", nCount);
delete [] pDataArray;
return 0;
}
This prints
9 8 7 6 5 4 3 2 1 0
Sum total is 45

C++ Class, Assigning values during Constructor initialization

I have a 2D array which I declared part of the classes private members. When I call the constructor, I start assigning values to the 2D array. But every time I do so, I'm hit with an error C2059. To make sure nothing else was causing that error I commented out that line and the compiler finished putting together a binary file.
tried:
Variable[row] = { 0, 1, 2, 3};
Variable[row][] = { 0, 1, 2, 3};
Variable[row][4] = { 0, 1, 2, 3};
No luck, any clues. Thanks in advance.
This syntax is only to be used for the creation of the object.
int array[4] = {1, 2, 3, 4};
Once the array is created, you have to use a loop to assign values to it.
Here's a short example :
class A
{
int array[4];
public:
A()
{
// Here, array is already created
// You can _assign_ values to it
}
};
If you want to give it values when it's instantiated in the constructor, the only way is to use initialization lists. Unfortunatly, you can't do this with a static array.
See this this thread.
Unfortunately, we can't yet properly initialize arrays that are members of classes. I don't know exactly how yours is declared, but here's an example of what to do:
class X
{
int Variable[3][4];
public:
X()
{
const int temp[][4] = { { 1, 2, 3, 4}, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
const int sz = sizeof(Variable)/sizeof(**Variable);
std::copy(*temp, (*temp) + sz, *Variable);
}
};
Since your question is not clear enough, all I can do is demonstrating a simple example.
2D array is initialized as,
//you may "optionally" provide the size of first dimension
int arr[][4] = {
{1,2,3,4},
{11,12,13,14},
{21,22,23,24}
};
And is acessed as,
for ( int i = 0 ; i < 3 ; ++i )
{
for ( int j = 0 ; j < 4 ; ++j )
{
cout << arr[i][j] << endl;
}
}
Online demonstration at ideone : http://www.ideone.com/KmwOg
Are you doing similarly?

What is the best way to create a sub array from an exisiting array in C++?

OK, I am trying to get a sub array from an existing array and I'm just not sure how to do it. In my example I have a very large array, but I want to create an array from the last 5 elements of the array.
An example of what I am talking about would be:
int array1 = {1,2,3,...99,100};
int array2[5] = array1+95;
I know this isn't correct, but I am having some trouble getting it right. I want to get the elements 96 through 100 in array1 and put them into array2 but I don't want to copy the arrays. I just want array2 to start at the 96 element such that array1[96] and array2[0] would be pointing to the same location.
for this:
"such that array1[96] and array2[0] would be pointing to the same location."
you can do:
int *arr2 = arr1 + 96;
assert(arr2[0] == arr1[96] == 97);
A reference hack from a C programmer willing to subvert the type system to get what works:
int (&array2)[5] = (int (&)[5])(*(array1 + 5));
Now array2 will be an array for all intents and purposes, and will be a sub-array of array1, and will even be passable to that famous C++ array_size template function. Though the best way to handle this hackery is to hide it with more hackery!
#define make_sub_array(type, arr, off, len) (type (&)[len])(*(arr + off));
int (&array2)[5] = make_sub_array(int, array1, 5, 5);
Nice. Terrible by some standards, but the end result a) looks pretty neat, b) does exactly what you want, c) is functionally identical to an actual array, and d) will also have the added bonus (or mis-feature) of being an identical reference to the original, so the two change together.
UPDATE: If you prefer, a templated version (sort of):
template <typename T, size_t M>
T (&_make_sub_array(T (&orig)[M], size_t o))[]
{
return (T (&)[])(*(orig + o));
}
#define make_sub_array(type, array, n, o) (type (&)[n])_make_sub_array(array, o)
int (&array2)[5] = make_sub_array(int, array1, 5, 5);
We still have to pass the type. Since one of our arguments must be used as part the cast, we cannot cleanly (IMHO) avoid the macro. We could do this:
template <typename T, size_t M, size_t N>
T (&make_sub_array(T (&orig)[M], size_t o))[N]
{
return (T (&)[N])(*(orig + o));
}
int (&array2)[5] = make_sub_array<int, 15, 5>(array1, 5);
But the goal here is to make the calling code as clean as possible, and that call is a bit hairy. The pure-macro version probably has the least overhead and is probably the cleanest to implement in this case.
You can use boost::iterator_range to represent "slices" of arrays/containers:
#include <iostream>
#include <boost/range.hpp>
int main()
{
int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// Create a "proxy" of array[5..7]
// The range implements the concept of a random sequence containter
boost::iterator_range<int*> subarray(&array[5], &array[7]+1);
// Output: 3 elements: 5 6 7
std::cout << subarray.size() << " elements: "
<< subarray[0] << " "
<< subarray[1] << " "
<< subarray[2] << "\n";
}
Note that the iterator range "knows" about the size of the sub-array. It will even do bounds checking for you. You cannot get that functionality from a simple pointer.
The usefulness of Boost.Range will become more apparent once you learn about STL containers and iterators.
If you're into linear algebra, Boost.uBlas supports ranges and slices for its matrices and vectors.
For a completely different approach you could do something like.
vector<int> v0(array1 + 95, array1 + 100);
or
vector<int> v1(array1, array1 + 100);
vector<int> v2(v1.begin() + 95, v1.end());
This would make a real copy of the elements of your vector.
In C++ you can use an int pointer as an int array, so getting the array2 to start at item 96 in array1 is easy, but there isn't any way to give array2 a size limit, so you can do this
int array2[] = &array1[96];
or this
int *array2 = &array1[96];
but NOT this
int array2[5] = &array1[96]; // this doesn't work.
On the other hand, C++ doesn't enforce array size limits anyway, so the only real loss is that you can't use sizeof to get the number of elements in array2.
note: &array1[96] is the same thing as array+96
edit: correction - int array[] = &array[96] isn't valid, you can only use [] as a synonym for * when declaring a function parameter list.
so this is allowed
extern int foo(int array2[]);
foo (&array1[96]);
int array1[] = {1,2,3,...99,100};
int *array2 = &array1[96];
int arr[] = { 1, 2, 3, 4, 5};
int arr1[2];
copy(arr + 3, arr + 5, arr1);
for(int i = 0; i < 2; i++)
cout << arr1[i] << endl;
The code is not safe if the boundaries are not handled properly.
You said you don't want to copy the array, but get a pointer to the last five elements. You almost had it:
int array1[] = {1,2,3,...99,100};
int* array2 = &array1[95];