I'm implementing Binary search. But I don't want to pass the size of an array as an argument in the binarySearch function. I'm trying to find array size in function. I use sizeof operator, but the output of the binary search is wrong. when I try to pass the size of array as an argument then the output is fine. My question is why & what is the problem for calculating array size in function? is it possible to calculate array size in function?
Here is my approach:
code
#include <bits/stdc++.h>
using namespace std;
void binarySearch(int arr[], int value)
{
int c = sizeof(arr) / sizeof(arr[0]);
//cout << c;
int low = 0, high = c - 1, notFound = 1;
while (low <= high)
{
int mid = (low + high) / 2;
if (arr[mid] == value)
{
cout << "Found at index " << mid << endl;
notFound = 0;
break;
}
if (arr[mid] < value)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
if (notFound == 1)
{
cout << "Not Found" << endl;
}
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 9, 56, 88};
int x = 3;
binarySearch(arr, x);
//cout << p << endl;
}
output:
tempCodeRunnerFile.cpp:5:22: warning: 'sizeof' on array function parameter 'arr' will return size of 'int*' [-Wsizeof-array-argument]
int c = sizeof(arr) / sizeof(arr[0]);
^
tempCodeRunnerFile.cpp:3:23: note: declared here
void binarySearch(int arr[], int value)
~~~~^~~~~
Not Found
My expected Output:
Found at index 2
My question is why & what is the problem for calculating array size in function
The problem is that arr is a pointer to an element of the array. The size of the pointer has nothing to do with the size of the array, which is why your attempted sizeof(arr) cannot work.
The warning message also explains this quite well.
is it possible to calculate array size in function?
Given only a pointer to an element, it is generally1 not possible to determine the size of the array. That is why you must pass the size as an argument.
Another approach which I prefer is to encapsulate the pointer and the length in a class. There is a standard class template for this purpose: std::span.
void binarySearch(std::span<int> arr, int value)
{
int c = arr.size();
...
// call as in your example:
int arr[] = {1, 2, 3, 4, 5, 6, 9, 56, 88};
int x = 3;
binarySearch(arr, x);
1 There are techniques that allow this, but they have draw backs.
One technique is to choose one element value as a "terminator" aka "sentinel" which signifies the end of the array. That way, you can do a linear search for the terminator to determine the length. This is commonly used in C with strings, where the null terminator character terminates the string. This technique isn't an option if you cannot dedicate any of the values as a terminator. The other obvious drawback is the linear complexity of the size calculation which is asymptotically more expensive than the binary search that you're implementing
There is a further possibility that you could use, but calling it with too many different array sized might cause code bloat.
template<std::size_t N>
void binarySearch(int arr[N], int value)
And then use N instead of c.
Related
I have just written a binary search on c++, using arrays, but it isn't working for all of my tests.
#include <iostream>
using namespace std;
int bSearch(int arr[], int item);
int main() {
int testArr[] = {1, 3, 5, 7, 9, 10, 12, 13, 15, 16, 18, 20};
int result = bSearch(testArr, 18);
cout << "The result of binary search is " << result << endl;
return 0;
}
int bSearch(int arr[], int item) {
int start = 0;
int middle(0), guess(0);
int finish = sizeof(arr);
while(start <= finish) {
middle = (start + finish) / 2;
guess = arr[middle];
if(guess == item)
return middle;
else if(guess > item)
finish = middle - 1;
else
start = middle + 1;
}
return -1;
}
Can you explain me, why is it so?
In bSearch, the parameter arr is not an array, but a pointer to an int. There is no information on if it points to an array of ints or the number of elements may be part of such an array.so sizeof(arr) will be the size of a pointer (typically 4 or 8).
You'll need to pass number of elements the array holds to bSearch, or use one of the standard containers that track the size (std::vector or std::array).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Do the conditions of the for-loop always need constant?
How can I put sizeof function there to run an output showing all the elements of an array?
#include<iostream>
using namespace std;
void array_output(int a[])
{
for (int i = 0; i < (sizeof(a)) / (sizeof(a[0])); i++)
{
cout << a[i] << endl;
}
}
int main()
{
int a[] = { 22, 53, 13, 65, 80, 31, 46 };
array_output(a);
return 0;
}
i<(sizeof(a) output shows first 4 elements
i<(sizeof(a))/(sizeof(a[0])) output shows only the first element
instead of sizeof when 7 is directly used as a condition, it gives
the right output, showing all the elements.
†(This answer is for c++17 users...)
where no need of using sizeof operator at all.
Use instead std::size() function which will get you the size of the given container or array.
#include <iostream>
#include <iterator> // std::size
#include <cstddef> // std::size_t
int main()
{
int a[]{ 22,53,13,65,80,31,46 };
for (std::size_t i = 0; i < std::size(a); i++)
{
std::cout << a[i] << `\n`;
}
}
† Update
The OP has edited the question after posting this answer,
where the std::size can not be applied.
When the array a passed to void array_output(int a[]), it deduced to void array_output(int* a)
instead if of the its actual type int a[7].
i<(sizeof(a) output shows first 4 elements
Here, you are doing size of(int*) (pointer to int), depending up
on the architecture
it could be efferent. In your case it is 32 bit machine which is why you got sizeof(a) = 4.
i < sizeof(a)/ sizeof(a[0]) output shows only the first element
Dividing sizeof(a)(which is sizeof(int*) equal to 4 bytes in
your machine) by sizeof(a[0])(which is sizeof(int), also 4 bytes), is nothing but one and loops only once.
The #Timo's
answer, provide a templated function where size will be a non-type template parameter, which can be accessed directly, without going for sizeof.
How can I put sizeof in function and run an output showing all the
elements of an array?
This is possible only when passing the array a of actual type as it is.
For that, let the array to deduce to its int [7], by forwarding it perfectly.
#include<iostream>
template<typename Type>
void array_output(Type&& a) // deduced to `int a[7]`
{
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) { // or std::size(a)
std::cout << a[i] << '\n';
}
}
int main()
{
int a[] = { 22, 53, 13, 65, 80, 31, 46 };
array_output(a);
return 0;
}
If you use the actual array in the sizeof operator you will get the size of the array in bytes, meaning you can calculate the number of elements like you expected it using sizeof(array) / sizeof(array_type).
int x[] = {1, 1, 1, 1, 1, 1};
int sum = 0;
for (int i = 0; i < sizeof(x) / sizeof(int); i++)
sum += x[i];
// sum == 6
However if you pass the array as a function parameter you will encounter pointer decay. This means that the array size information is lost and you get the pointer size instead, which is the behavior that you described.
int sum(int arr[]) // arr decays to int*
{
int sum = 0;
for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
sum += arr[i];
return sum;
}
int main()
{
int x[] = {1, 1, 1, 1, 1, 1};
return sum(x); // will return 1 or 2, depending on architecture
}
You can still get the array size in the function if you use a template function for it.
#include <cstddef>
template <std::size_t N>
int sum(int (&arr)[N])
{
int sum = 0;
for (int i = 0; i < N; i++)
sum += arr[i];
return sum;
}
int main()
{
int x[] = {1, 1, 1, 1, 1, 1};
return sum(x); // will return 6
}
You can use vector for this.
vector<int> nums{1,2,3,4};
for(std::size_t i = 0; i < nums.size(); ++i)
cout<<nums[i]<<endl;
If you insist on using int a[], you should be aware of the size before traversing it.
By the way, on GCC
sizeof(nums) = sizeof(int) * total number of element
it's not the total number of element.
This is the code to find a number in the array and return its index. But what if I have the same 2 numbers and I want to return both their indexs ?
int find_pos (int a[], int index, int n)
{
if ( a[index] == n)
{
return index;
}
else
{
return find_pos (a, index + 1, n);
}
}
int main()
{
int a[] = {3, 1, 5, 6, 0, 6, 8, 4};
cout << find_pos (a, 0, 6);
}
You could use a vector<int> to hold the indices of found values. That is, instead of returning when you find a matching value, just save the index into your vector and continue searching. This means that your recursion base case has to change. You'll have to search all the way to the end of the array. Since you're using a C-style array, you'll have to also pass in the length of the array too, so that recursive function calls can know when to stop.
This question already has answers here:
Why isn't the size of an array parameter the same as within main?
(13 answers)
Closed 8 years ago.
Trying to pass an int array of consecutive numbers starting with 1 but assuming the function receiving this array does not know it's length. When trying to calculate the length inside the function it just gives me 1 since it only finds the first element when calculating sizeof(arrayName).
#include <iostream>
using namespace std;
int Sum(int intArray[]) {
int n = sizeof(intArray) / sizeof(*intArray);
cout << "Array size in function: " << n << endl;
return n * (n + 1) / 2;
}
int main() {
int anArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int arraySum = Sum(anArray);
cout << "Array size in main: " << sizeof(anArray) / sizeof(*anArray) << endl;
cout << "Sum is: " << arraySum;
int a;
cin >> a;
return 0;
}
Your function is taking a pointer to int. All size information is lost as you pass the array into the pointer. But you can use a function template to instantiate functions that match the right array size:
template <size_t N>
int Sum(const int (&intArray)[N])
{
cout << "Array size in function: " << N << endl;
return std::accumulate(std::begin(intArray), std::end(intArray), 0);
}
This Sum function will accept plain arrays or size known at compile time. However, it makes more sense to use std::array for these cases, or std::vector for cases when the size is chosen at runtime.
Note that the call to std::accumulate is just an example that solves the sum problem. It does not require knowledge of N, and could replace the function entirely. The size is taken care of by std::begin and std::end. You would need headers <numeric> and <iterator> for accumulate and begin/end respectively.
In this function declaration
int Sum(int intArray[]);
array passed to it as an argument is implicitly converted to the pointer to the first element of the array. So this declaration is equivalent to
int Sum( int *intArray );
And the expression
int n = sizeof(intArray) / sizeof(*intArray );
is equivalent to
int n = sizeof( int * ) / sizeof( int );
if sizeof( int * ) is equal to sizeof( int ) then n will be equal to 1.
If you declare the parameter such a way as you did then you should also declare a second parameter that will accept the number of elements in the array. So I would rewrite the function the following way
int Sum( int intArray[], size_t n )
{
int sum = 0;
for ( size_t i = 0; i < n; i++ ) sum += intArray[i];
return sum;
}
and in main I would call the function the following way
int arraySum = Sum( anArray, sizeof( anArray ) / sizeof( *anArray ) );
}
Also functions ususally are written to perform some general algorithms. It is a bad idea to write a function only for arrays that has sequantial values from 1 to some N.
This question already has answers here:
Why does a C-Array have a wrong sizeof() value when it's passed to a function? [duplicate]
(6 answers)
Closed 9 years ago.
#include <stdio.h>
#include <iostream>
using namespace std;
int write(int arr[])
{
int n = (sizeof(arr)/sizeof(arr[0]));
for(int r=0;r<n;r++)
{
printf("%d\n", arr[r]);
}
return 0;
}
int main()
{
int numlist[] = {1, 3, 5, 6, 7, 9, 0, 2, 3};
write(numlist);
std::string strvar;
std::cin >> strvar;
}
What is being printed on the screen is just the number '1'. Nothing more.
Just beginning C and I'm only trying to get the hang of the syntax.
You cannot compute the size of the array inside the function using
(sizeof(arr)/sizeof(arr[0]));
That is because the function only sees arr as a pointer (the array decayed into a pointer), not as a full array. Thus, n will be 1.
You have to pass the size as an extra argument.
int write(int arr[], int n)
{
for(int r=0;r<n;r++)
printf("%d\n", arr[r]);
return 0;
}
and call it with
write(numlist, sizeof(arr)/sizeof(arr[0]));
Inside
int write(int arr[])
arr is a int*. sizeof(arr)/sizeof(arr[0]) comes out as 1 for you because pointers have the same size as integers on your system.
You can only calculate the number of elements in an array when you have access to its definition. In your case, this is inside main only. If you want to pass the array to another function you also need to pass its length
int write(int* arr, size_t num_elems)
{
for(int r=0;r<num_elems;r++) {
printf("%d\n", arr[r]);
}
return 0;
}
int main()
{
int numlist[] = {1, 3, 5, 6, 7, 9, 0, 2, 3};
size_t num_elems = sizeof(arr)/sizeof(arr[0]);
write(numlist, num_elems);
}
Alternatively, if you define a sentinel value that marks the end of the array, you don't need to pass a length
int write(int* arr)
{
while (*arr != -1) {
printf("%d\n", *arr);
arr++;
}
return 0;
}
int main()
{
int numlist[] = {1, 3, 5, 6, 7, 9, 0, 2, 3, -1}; /* element with value -1
marks the end of the
array */
write(numlist);
}
The problem is the following line
int n = (sizeof(arr)/sizeof(arr[0]));
In this context C has no idea what the length of arr is. Arrays in C just don't have an inherent length property. Hence when you say sizeof(arr) it translates into 1 not the number of elements.
In order to make this work you need to explicitly pass the number of elements in the array to the function along with the array
int n = (sizeof(arr)/sizeof(arr[0])); does not work in this context, since arr is a function parameter which has decayed to a pointer at this point. Either pass the number of elements to the function or use a sentinel value to mark the end of the array.
in C/C++, when arrayname passed as parameter, it's convert to an pointer.
so in that function sizeof(arr) is and equal to sizeof(int*).
int C++
int a[10];
int (&b)[10] = a; // b is a reference of int array whose length is 10;
//so here could be ok
template< size_t n>
size_t write(int (& new_array_name)[n])
{
//
}
On 64 bit Operating System, sizeof(arr[0]) is returning 4 bytes while sizeof(arr) is returning 2 bytes. On my system, n has value 2. Due to this reason, loop is executing r<2 times on my system. On 32 bit Operating system, sizeof(arr[0]) returns 2 bytes instead of 4 bytes. That's why you are getting index 0 of arr to be executed only.