This is very similar to not providing a null terminator for a character array that will be used as a string.
while(*arr)
means stop when you find a zero.
int arr[3] = {1,2,3};
provides no zero, therefore you have no control over when the loop will stop.
TL;DR Solution:
Use a Library container. std::vector or std::array
would be a good fit here, as would std::count
from the <algorithm>
library and std::begin
and std::end
from the <iterator>
library.
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
int arr[] = { 1, 2, 3 };
int count = std::count(std::begin(arr), std::end(arr), 1);
std:: cout << count;
}
Explanation:
You could provide a zero
int arr[] = {1,2,3,0};
Note I remove the explicit array size. It's not needed because the compiler knows from the number of elements in the initialzer.
Note also that this will stop upon reaching the first zero, so
int arr[] = {1,2,3,0,1,2,3,0};
will only spot one 1. This makes zero a very poor value to use to terminate a list of integers unless 0 is guaranteed to not be in the input.
To scan the whole array and only the array, the size of the array needs to be provided. This can be done by passing in a size parameter
int counter(int* arr, size_t len, int c)
{
int counter = 0;
while (len--)
{
std::cout << *arr << "\n";
if (*arr == c)
{
++counter;
}
++arr;
}
return counter;
}
int main()
{
int arr[3] = { 1, 2, 3 };
int count = counter(arr, std::size(arr), 1);
std:: cout << count;
}
but the preferred solution in Modern C++ would be to use a container in place of the array. Containers know their size and offer up a wide variety of other tools to make writing code easier and less error-prone.
#include <iostream>
#include <vector>
int counter(const std::vector<int> & arr, int c)
{
int counter = 0;
for (const auto & val: arr)
{
std::cout << val << "\n";
if (val == c)
{
++counter;
}
}
return counter;
}
int main()
{
std::vector<int> arr = { 1, 2, 3 };
int count = counter(arr, 1);
std:: cout << count;
}
Note the use of a range-based for loop to simplify the code. const auto & val
deduces the type of val
from the contents of arr
with auto
. The value is not going to be changed as a result of the loop so we declare it const
to prevent accidents and make it a reference because maybe the compiler can pull off some extra optimization voodoo. In addition you can keep reusing this exact statement without having to change a thing if the container or the type of data in the container is ever changed. This prevents mistakes later when maintaining the code.
You could also use std::array
and make counter
a templated function that detects the size of the std::array
here, but that's a bit much at this point.
The next evolution takes advantage of the <algorithm>
library.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> arr = { 1, 2, 3 };
int count = std::count(arr.begin(), arr.end(), 1);
std:: cout << count;
}
In this case Iterators are being used rather than specifying lengths. This lets you easily scan subsets of a container.
This allows us to go back to using a vanilla array by taking advantage of std::begin
and std::end
to turn the array into a pair of iterators :
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
int arr[] = { 1, 2, 3 };
int count = std::count(std::begin(arr), std::end(arr), 1);
std:: cout << count;
}
And that brings us around to the TL;DR solution.