Issue about Binary search algorithm in c - c

I am confused in understating the behavior of the code while searching for an element which does not exist in the array.
The result of the element index i am looking for is always zero while declaring it as int index;.
The result of the element index i am looking for is random number while declaring it as size_t index;
what is the difference between declaring the variable index as int index; andsize_t;in the code below.
The code
#include <stdio.h>
#define SIZE 5
int main(void)
{
int numbers[SIZE]={1,2,3,4,5};
int search =0; // This variable define the required number i am searching for
int start = 0 ;
int end = SIZE-1 ;
size_t index;
while (start <= end)
{
int middle = (start+end)/2;
if (search == numbers[middle])
{
index = middle;
}
if (search > numbers[middle])
{
start = middle+1 ;
}
else
{
end= middle-1 ;
}
}
printf("The index of the element is %d",index);
return 0;
}

The basic problem is that index is not initialized and that it never gets assigned when you don't find what you are searching for. Since the printf statement accesses an uninitialized variable in that case, your code have undefined behavior, i.e. anything may happen - including print of all sorts of numbers.
The result of the element index i am looking for is always zero while declaring it as int index;
That is "just by luck"
The result of the element index i am looking for is random number while declaring it as size_t index;
That is also "just by luck"

Here are a couple of action items you can take to improve your code:
Since this array is statically defined there is no need to include the SIZE define inside the []. Declare it like this int numbers[]={1,2,3,4,5}; instead of this int numbers[SIZE]={1,2,3,4,5};. Let the compiler do the math for you.
Initialize index to some value (i.e. index = 0;). this is the main cause of the problem and it is introducing undefined behavior to the program.
Change the type of size_t index to int index every variable that was declared in the program is an int and the program is treating index as an int. So it might as well be an int to avoid confusion.
Make this an else if clause instead of just an if:
else if (search > numbers[middle])
{
start = middle+1 ;
}
Add another case to have the program fail gracefully when the value to be searched is missing from the data set. Such as, printf("Data not found: %d", search);
The algorithm still isn't 100% and has some flaws but I will leave this up to you to figure out. I hope this info helps!
Best Regards!

The problem is that , the value of indexis not initialized.
initializing the variable to 0 does not solve your problem.
Because you are using index to return the position of the array element.
By initializing the index = 0 will provide he same result for the elements not present in the array as well as the for the first element to the of the array .
The better way is to initialize as size_t index = -1;
So that the result for the elements not present in the array would b -1.
Also check for the access specifier used in the printf statement, for size_t datatype. It can be ,
printf("The index of the element is %ld",index);

You are not using correct specifier for size_t, it's not %d.
Try to use %zd or %ld and it'll work fine.
Furthermore, add this after the while loop so that it doesn't show weird value of index when the element is not present in the array.
if(start>end) {
printf("That number is not present in the array");
return 0;
}
And move the line printf("The index of the element is %d",index); under the condition if (search == numbers[middle]). So that you don't get "this number is not present" even if it is present in the array.
For corrected version of your code see https://code.hackerearth.com/80043dg?key=7b325b26aec0f5425b76cc3efbdc93cf

Related

How do I find the number of element of an array which have their size previously undefined

I'm trying to make an array which have it's element coming from a user input. This array would first have it's size undefined since we don't know how much int would the user input, but then I'm not able to find the amount of element in the array like this unless I put a counter on the loop function.
Here is the code that I've made:
int cross[] = {0};
int k;
for (k = 0; k >= 0; k++){
scanf("%d", &cross[k]);
if (cross[k] == -1){
break; //stop the user from inputing numbers if user input -1
}
int p = sizeof(cross) / sizeof(cross[0]);
If I were to do printf("%d", p), it would always give me 1 as a result. I'm wondering if there is any other way of doing this other than putting a counter on the for loop.
Thanks!!
This phrase from your question is both wrong and dangerous: "This array would first have it's size undefined".
The following line of code defines a fixed-size array that has exactly one element:
int cross[] = {0};
The compiler knows it's one element because you supplied one initializer value {0}. If you supplied this {0, 5, 2}, it would allocate 3 integers, and so on.
This means when you store into cross[k] and k is larger than zero, you're actually exceeding the bounds of your allocated array, which C doesn't catch at compile time, but could cause nasty problems at run time.

local and global arrays and segmentation fault

I'm having trouble with the following: I want to take a large number (cca. 15-digit) and turn it into individual digits and store them in an array. I will need these digits further on in the code. The problem is, if I declare the array outside the while loop, it stores the first four values, but then I get a segmentation fault. If I declare it within the loop, the code works as I want it to, but then I don't know how to move the array out of that loop, so that I could use it further. How can I solve this? This is what I've compiled:
unsigned long long card_num;
printf("Enter your credit card number:\n");
scanf("%llu", &card_num);
int count = 0;
while (card_num != 0)
{
int digits[count]; //declaring array into which digits will be stored
digits[count] = card_num%10; // get last digit, store it in array
card_num = card_num/10; //remove last digit
printf("Digit[%i] = %i\n", count, digits[count]);
printf("Number of digits: %i\n", count);
count ++;
}
In your code, for the very first iteration
int digits[count];
count is 0, which violates the constraints mentioned in spec. As per C11, chapter 6.7.5.2,
In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero. [....]
and
If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *; otherwise, each time it is evaluated it shall have a value greater than zero
So, this is not a valid code.
As already mentioned, what you are doing is plain wrong.
There is several ways to solve this issue. The easiest would be to allocate an array at the beginning of your program with enough space for all your usecases with something like :
#define MAX_DIGIT 50
int digits[MAX_DIGIT];
Then you just have to check you are not going over this array by checking that count < MAX_DIGIT.
Another way would be using dynamic memory allocation using an int pointer int *digits and malloc (I let you google that) once you know the size of the array you'll need. You'll have to change a bit your code to know the number of digits before starting to get the digits as you need to allocate the memory before starting to store digits.
You could use realloc to keep a code similar to what you already have, but I wouldn't advise it as it is not efficient to realloc memory for each value that you add.
Your logic is fine.
What went wrong is that you tried to increase the length of a fixed-length array while iterating which is not allowed.
You should never change the length of a fixed-length array anywhere in the program.
However if you want to change the length of an array during runtime you must use the malloc and realloc functions to do so.
Check out this example:
//declarations
int *storeNum;
storeNum = (int *)malloc(1 * sizeof(int));
//logic
while(num != 0) {
if(i > 0)
storeNum = realloc(storeNum, (i+1) * sizeof(int));
storeNum[i] = num % 10;
num = num/10;
++i;
}
Here first I declared the array size initially as one and later incremented it using realloc function.
You also have the array size stored in i which you can use later in your code in loops.
But keep in mind that the digits will be stored in your array in reverse order.
Also, you shouldn't declare an array within a loop.
Since you have "declared" the array, each time the compiler enters the loop while iterating it will consider the array-declaration as a new array. That is all.

Pass array as parameter in C

My professor suggested that we should also pass a integer size as the parameter :
int abc(const int data[], int size, int value) {
int i= 0, ans= -1;
while (i < size && ans == -1) {
if (data[i] == value)
ans= i;
i++;
}
return ans;
}
However, I don't think it is necessary to add the integer size in the parameter.
I think the function can be changed to:
int abc(const int data[], int value) {
int i= 0, ans= -1;
while (data[i]!=NULL) {
if (data[i] == value)
ans= i;
i++;
}
return ans;
}
(I know that we are just passing the pointer of the first element of the array in to the function!)
Is the first version has more advantage than the second version?
data[i] being an int value should not be compared against NULL. That's just not correct.
You should pass the size as a separate parameter.
Passing the size as a parameter is a good practice that can protect you from a segmentation fault if the array is malformed.
If you are absolutely certain that the array will contain 0 (which is what NULL is) as a last value, and only as the last value, your solution would also work.
However, if 0 is a valid value in the array, then you will stop as soon as you encounter it.
while (data[i]!=NULL) - there is no guarantee that data[size] would be equal to NULL as you suggested it would be. Without specifying size of the array, the value of data[size] could in fact be anything.
Note that accessing an array out-of-bound results in undefined behaviour. You will just get whatever value left over in that particular memory location, which can be gibberish, and no guarantee of any specific value (including NULL).
Yes, the first version has one major advantage: it actually works!
There are two reasons why yours won't:
Your version loops until NULL is found. NULL is either a pointer to 0 (which will not work), or 0. So what if there are zeroes in the array? You will get early termination.
Your version has not way of knowing when to stop. What if value is not found in the array? You will go on and on and on until there just happens to be 0 in memory. Arrays are not terminated with 0, only character literals are.
data[i]!=NULL for this to work, the element after the last element of the array should be NULL, which I think won't be the case. int cannot be compared with NULL.
However, you can do something similar. You can use a marker to mark the end of the array
Choose some number that you are sure won't appear in the array (may be you know the range of numbers in the array), lets say 99999. Then save it after the last element (do remember you need an array of size one more then the elements you wanna keep). And then use that to check the end of array.
int abc(const int data[], int value) {
int i= 0, ans= -1;
while (data[i]!=99999) {
if (data[i] == value)
ans= i;
i++;
}
return ans;
}
If there is no information about the range
Then you have to send the size of the array along with other parameters to the function.

What's the point of using linear search with sentinel?

My goal is to understand why adopting linear search with sentinel is preferred than using a standard linear search.
#include <stdio.h>
int linearSearch(int array[], int length) {
int elementToSearch;
printf("Insert the element to be searched: ");
scanf("%d", &elementToSearch);
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
return -1; // The element to be searched is not in the array
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10};
int myArrayLength = 6;
linearSearch(myArray, myArrayLength);
return 0;
}
Wikipedia mentions:
Another way to reduce the overhead is to eliminate all checking of the loop index. This can be done by inserting the desired item itself as a sentinel value at the far end of the list.
If I implement linear search with sentinel, I have to
array[length + 1] = elementToSearch;
Though, the loop stops checking the elements of the array once the element to be searched is found. What's the point of using linear search with sentinel?
A standard linear search would go through all the elements checking the array index every time to check when it has reached the last element. Like the way your code does.
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
But, the idea is sentinel search is to keep the element to be searched in the end, and to skip the array index searching, this will reduce one comparison in each iteration.
while(a[i] != element)
i++;
First, lets turn your example into a solution that uses sentinels.
#include <stdio.h>
int linearSearch(int array[], int length, int elementToSearch) {
int i = 0;
array[length] = elementToSearch;
while (array[i] != elementToSearch) {
i++;
}
return i;
}
int main() {
int myArray[] = {2, 4, 9, 2, 9, 10, -1};
int myArrayLength = 6;
int mySearch = 9;
printf("result is %d\n", linearSearch(myArray, myArrayLength, mySearch));
return 0;
}
Notice that the array now has an extra slot at the end to hold the sentinel value. (If we don't do that, the behavior of writing to array[length] is undefined.)
The purpose of the sentinel approach is to reduce the number of tests performed for each loop iteration. Compare:
// Original
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i;
}
}
return -1;
// New
while (array[i] != elementToSearch) {
i++;
}
return i;
In the first version, the code is testing both i and array[i] for each loop iteration. In the second version, i is not tested.
For a large array, the performance difference could be significant.
But what are the downsides?
The result when the value is not found is different; -1 versus length.
We have to make the array bigger to hold the sentinel value. (And if we don't get it right we risk clobbering something on the stack or heap. Ouch!)
The array cannot be read-only. We have to be able to update it.
This won't work if multiple threads are searching the same array for different elements.
Using the sentinel value allows to remove variable i and correspondingly its checking and increasing.
In your linear search the loop looks the following way
for (int i = 0; i < length; i++) {
if (array[i] == elementToSearch) {
return i; // I found the position of the element requested
}
}
So variable i is introduced, initialized, compared in each iteration of the loop, increased and used to calculate the next element in the array.
Also the function has in fact three parameters if to pass to the function the searched value
int linearSearch(int array[], int length, int value) {
//...
Using the sentinel value the function can be rewritten the following way
int * linearSearch( int array[], int value )
{
while ( *array != value ) ++array;
return array;
}
And inside the caller you can check whether the array has the value the following way
int *target = linearSearch( array, value );
int index = target == array + size - 1 ? -1 : target - array;
If you add the value to search for, you can reduce one comparison in every loop, so that the running time is reduced.
It may look like for(i = 0;;i++) if(array[i] == elementToSearch) return i;.
If you append the value to search for at the end of the array, when instead of using a for loop with initialization, condition and increment you can a simpler loop like
while (array[i++] != elementToSearch)
;
Then the loop condition is the check for the value you search for, which means less code to execute inside the loop.
The point is that you can convert the for loop into a while/repeat loop. Notice how you are checking i < length each time. If you covert it,
do {
} while (array[i++] != elementToSearch);
Then you don't have to do that extra checking. (in this case, array.length is now one bigger)
Although the sentinel approach seems to shave off a few cycles per iteration in the loop, this approach is not a good idea:
the array must be defined with an extra slot and passing its length as 1 less than the defined length is confusing and error prone;
the array must be modifiable;
if the search function modifies the array to set the sentinel value, this constitutes a side effect that can be confusing and unexpected;
the search function with a sentinel cannot be used for a portion of the array;
the sentinel approach is inherently not thread safe: seaching the same array for 2 different values in 2 different threads would not work whereas searching a constant read only array from multiple threads would be fine;
the benefits are small and only for large arrays. If this search becomes a performance bottleneck, you should probably not use linear scanning. You could sort the array and use a binary search or you could use a hash table.
optimizing compilers for modern CPUs can generate code where both comparisons will be performed in parallel, hence incur no overhead;
As a rule of thumb, a search function should not have side effects. A good example of the Principe of least surprise.

How to set an "empty" element in any part of an Array in C

I'm doing a program to insert numbers in an array, simple thing here, for example:
if(menu==1){
system("cls");
result=lastposition(array,20);
if(result==25){
printf("\n Error! The array is FULL!");
printf("\n Press Enter to continue");
getch();
} else{
printf("\n\n\tOption 1 selected: \n");
printf("\n Type the number to add it to the array: ");
scanf("%i",&value);
if(array[0]!=NULL){
printf("\n The first space is already filled, moving itens");
changeplace(array,20,value);
printf("\n Items moved with success!\n");
}else {
array[0] = value;
}
printf("\n Number %i added!\n",value);
printf(" Press to continue.\n");
getch();
}
So, what this does is, you type a number, and it inserts in a 20 positions array, in its first position (that's why the function "lastposition" is there, to check the lastposition filled in the array), if the first position is not filled yet(NULL), it adds in the first position, if it is already filled, the "chageplace" function moves all the values to the right, and then adds the number!
My problem is, when i declared the array, i set all its values to NULL, like this: int array[20]={NULL};! But in C, NULL change all its values to 0, and if someone in my program add 0 as a value, lets say the array already got a 5 and a 10 on it, like this [5][10][0][0][0]...[0], I'll add the zero, getting like this: [0][5][10][0][0]...[0], till there ok, but because C considers NULL=0, when i try to add another number it will check if the first position is already filled (it'll check if it's NULL, or 0, and it will return as NULL [0]), and if i try to add a 7 on it, it will replace the 0 (the added number, not the NULL) and it will get like [7][5][10][0][0]...[0]
Anyone knows how to fix this? Someway to be able to add a 0 in the function, without it being replaced by the next number because it's considered NULL? Having a real "Nothing" there, instead of "0".
PS: I cant just put random numbers in the array, to be different of 0, for 2 reasons, first, option 3 of the menu show the vector [therefore showing the random number, and 2, my function would consider it as already filled by a number!
PSĀ²: The "25" that the "lastposition" function returns is just a random number I've set to return if the last position of the array is 20 (meaning its already full)...
This is simply not possible in C. One workaround might be to change the array elements into a struct having a field used being a boolean and a field data being an int.
You can use another sentinel value to represent "not used". Say INT_MAX or INT_MIN.
You can use negative values for instance. But it's really dirty hack).
NULL is a pointer. Assigning it or comparing to any other type (like int) should at least produce a warning from the compiler. Do you enter pointers from the console?
Integer scalars mostly do not have reserved codes (and if, that would be implementation defined). So you need something out-of-band to signal "empty".
YOu can either restrict the valid range of values and use a value outside that range as "empty" tag. Or use an additional flag per entry. For float, there are similar ways, e.g. using NaN.
Version with seperate flag using a struct:
#include <stdbool.h>
struct {
bool valid;
int value;
} array[20];
Version with INT_MIN as reserved value:
#include <limits.h>
#define VALID_MIN (INT_MIN - 1)
#define EMPTY_VALUE INT_MIN
for ( int i = 0 ; i < sizeof(array) /sizeof(array[0]) ; i++ )
array[i] = EMPTY_VALUE;
....
int value;
do {
value = input_value(); // ...
} while ( value < VALID_MIN ) ;
....
You should simply track the number of filled elements in the array. :)
In C, NULL is practically always a zero cast to a pointer, which is why you are seeing a zero. There is no special "empty" value, and you shouldn't ever use NULL when dealing with integers.
One way to do this, is to have another array of booleans that will say whether it is empty or not. For example
_Bool isFull[25] = {0}; // Initialize it to all FALSE.
Then instead of checking array[i] == NULL, you check if isFull[i] == FALSE.
When adding an element (including 0), you set isFull[i] = TRUE;.
You can use a value that should not be a part of the array itself. (which means that you shouldn't input that value in the array anymore if you use it as the indicator of occupied index.) But your program will be less flexible that way since you cannot input any value you want.
Another is to use struct, which will hold one variable for the value itself, and another as indicator if it is filled or not. (it can be a boolean or int which can only 0 or 1).
struct values {
int value;
int indicator; // or bool indicator, make sure to include stdbool.h
} array[20];
One trick to accomplish what you want (adding on the top/front of the array) without using indicators of occupied index is to fill the array backwards. No moving of previous inputs to the right is also needed.
int i = max_elements; // lets say max_elements = 20
printf("\n Type the number to add it to the array: ");
scanf("%i",&value);
array[i] = value; // will fill array[20]
i--; // so that the next input will go to array[19], and so on...
But if you really want to go with changing positions,
int const_index = 0;
printf("\n Type the number to add it to the array: ");
scanf("%i",&value);
array[const_index] = value;
// change positions
for (i = max_elements; i > 0; i--)
array[i + 1] = array[i];
const_index = 0;
Or a better option is to use stack data structure.
You can take a look here on how to do it.
C Program to implement Stack Operations Using Stack

Resources