Pass array as parameter in C - 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.

Related

Issue about Binary search algorithm in 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

Passing a 2d-array to a function in C

Note I'm using C not C++. I'm working on a program that will take a 2d-array and count the numbers of non-spaces in a subarray. Such as lines[0][i] <-- iterating over line[0][0] - line[0][n]. However, I'm having difficulty getting the function to accept the 2d-array.
Here is my code:
pScore[0]=letters(pLines, 0);
This is the actual function. pScore[] is another array, but a 1d one. pLines is a 4 by 200 2d-array.
int letters(char line[][], int row)
{
int i = 0;
int n = n;
int results = 0;
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
{
if( !isspace(line[row][i]) )
results++;
}
return results;
}
When I do this it gives me "formal parameter number 1 is not complete". If I remove the second [] from it, the code runs but gives the worng number of non-space characters.
Taking from the comments above, and your function parameter list:
int letters(char line[][], int row)
You violate one primary tenant of passing a 2D array to a function. Specifically, you must always provide the number of columns contained in the array. e.g.
int letters(char line[][5], int row)
char line[][5] is an appropriate parameter. However, whenever you pass an array as a function parameter, the first level of indirection is converted to a pointer. (you will often here this referred to as "pointer-decay", though that is a bit of a misnomer). Therefore a proper declaration that makes this clear is:
int letters(char (*line)[5], int row)
line, after conversion, is a pointer-to-an-array of 5-int. While you can pass the array as line[][5], that is not nearly as informative as (*line)[5]. Let me know if you have any questions.
Numbers Instead of Characters
It is hard to tell what is going on without seeing the remainder of your code. However, I suspect that you are confusing the numerical value and the ASCII character value for the contents of your array. (e.g. character '0' = decimal 48 (0x30 (hex), '1' = 49, 'a' = 97, etc..). See ASCIItable.com
You you pass an array to a function it decays to a pointer. That means char line[][] should really by char (*line)[SIZE_OF_SECOND_ARRAY].
It also means the sizeof trick will not work, as doing sizeof on the pointer line will just return the size of the pointer and not what it points to, you need to explicitly pass the size as an argument to the function.
You need tell function the number of columns of 2d array. Here may help you.
I am not sure if the following statement works with you
for( i = 0; i < (sizeof(line)/sizeof(line[0])); i++ )
where sizeof(line) will be 4 or something like that depends on your platform because "line" is a pointer and you get the size of pointer itself.
Correct me if I am wrong.
In this case, you should pass column number as row's.

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

Array in c programming

I need help with this one:
Implement function int array_reader(int *array, int size) that reads integer values using scanf into pre-allocated array. Parameter size gives the maximum length of the array, and the maximum number of values to be read. If user does not give a valid integer (as can be seen from return value of scanf), the array ends, even if the maximum size was not yet reached. The function returns the final size of the array at the end, which can be smaller that the incoming size parameter, if the user finished the input with non-valid integer.
Below is an example how this function can be tested:
int array[10];
int n = array_reader(array, 10);
printf("%d numbers read\n", n);
I have done (but it is not ready yet):
int array_reader(int *array, int size)
{
int array[10];
scanf("%10d", &array[10]);
if (scanf("%10d", &array[10]) =! 10)
{
break;
}
}
Can you help me to continue? Thanks.
There is no function in standard C that can read into an array from a user like that, you have to loop over the array, reading values one by one.
You also have a few other problems:
You make a local variable array that shadows the argument, so you read only into that local array and not the one passed as the argument.
when you use 10 as index you are indexing out of bounds for the array. Indices range from zero to size - 1.
You don't return anything, even though you tell the compiler you would. That means that the assignment in the calling function will assign an unknown value.
The break statement does nothing outside of a loop.
The scanf function returns the number of values it converted, not the number of characters it read. So if you're scanning for only one item then scanf will return either 1, 0 or EOF.
For example like this
int array_reader(int *array, int size){
int count = 0;
do{
if(1!=scanf("%d", array++))
break;
++count;
} while(count < size);
//To be clear the buffer when there is bad input?
return count;
}
Thanks for answers!
You can make it also with for loop? Like this:
int array_reader(int *array, int size){
for(int count = 0; count < size; count++){
if(1!=scanf("%d", array++))
break;
else
return count;
}
}

Resources