C101: the best way to fill an array from user input? - c

I'm having a hard time understanding and therefore managing arrays and indexes manually in C. These are my two classic approaches but they doesn't seem to work as they keep looping when the condition is reached:
#include<stdio.h>
#define MAX 255
int main(){
int arr[MAX]={0};
int idx=0;
/* Approach #1 */
printf("Enter elements, -1 to finish:\n");
scanf("%d", &arr[idx]);
while(arr[idx-1] != -1 && idx < MAX){
printf("Enter elements, -1 to finish:\n");
scanf("%d", &arr[idx]);
idx++;
}
/* Approach #2 */
do{
printf("Enter elements, -1 to finish:\n");
scanf("%d", &arr[idx]);
idx++;
}while(arr[idx-1] != -1 && idx < MAX);
// Main func continues here.
}
Any advice would be much appreciated!
Update:
Now it works! thanks MUCH all of you guys for such instant responses. This is definitely a great community, it's helping me a lot.

arr[idx] <= MAX
should be
idx <= MAX

while(arr[idx] != -1 && idx <= MAX){ // Fixed by sklivvz
printf("Enter elements, -1 to finish:\n");
scanf("%d", &arr[idx]);
idx++;
}
First of all, you should check if the index variabel idx is smaller than MAX (not smaller than or equal to). You would go out of bounds if your index equals MAX. An array with MAX = 10 has index values 0 to and including 9, but not 10.
Secondly, you add the first element to arr[0], you increment your index from 0 to 1, then you jump back to the while-condition and check if arr[1] == -1, which it is not. So check instead that arr[idx-1] != -1. Note however that the first time you get to the while-loop, you will actually check arr[-1] != -1, which is also out of bounds. ;) So you need to figure out how to solve this one.

to Roman M:
First of all, the guy asking the question has just started a programming course, and has probably not yet learned about pointers. Secondly, you now deal with both a counter and a pointer. I'm not sure I see the benefit of doing that versus using an index like this:
for(idx=0; idx < MAX; ++idx) {
scanf("%d", &arr[idx]);
if(arr[idx] == -1)
break;
}

Using a for loop you can eliminate the need for the messy idx-1 checking code:
/* Approach #3*/
int i;
int value;
for (i = 0; i < MAX; ++i)
{
printf("Enter elements, -1 to finish:\n");
scanf("%d", &value);
if (value == -1) break;
arr[i] = value;
}

arr[idx] <= MAX
should be
idx < MAX
unless you are checking the item instead of the index.
You are also always checking the "next" element for -1 (arr[idx] != -1) because you are incrementing idx prior to checking your added value.
so if you had
arr[idx-1] != -1
you would be fine.

C arrays begin counting from 0.
If you allocate an array of size MAX, accessing the element at MAX would be an error.
Change the loop to;
int arr[MAX];
for ( .... && idx < MAX )

In your first while loop, the
arr[idx] <= MAX
line should read
idx <= MAX
In your second loop, you're incrementing idx before the test - it should end with
} while ((arr[idx-1] != -1) && (idx-1 <= MAX));
I also tend to parenthesize all internal conditions just to be absolutely certain that the precedence is correct (hence the extra brackets above).

I'd go with somthing like this.
You don't have to worry about array bounds and other confusing conditions.
int cnt = MAX; // how many elements in the array, in this case MAX
int * p = &arr[0]; // p is a pointer to an integer and is initialize to the address of the first
// element of the array. So now *p is the same as arr[0] and p is same as &arr[0]
// iterate over all elements. stop when cnt == 0
while (cnt) {
// do somthing
scanf("%d", *p); // remember that *p is same as arr[some index]
if (*p == -1) // inspect element to see what user entered
break;
cnt --; // loop counter
p++; // incrementing p to point to next element in the array
}

Related

A function that returns 0 or 1 if all elements in the range 0 to n-1 exist in the array, run time O(n)

EDIT:
I forgot to mention that I do not want to allocate another temporarily array.
I am trying to solve a problem in C, which is:
Suppose you were given an array a and it's size N. You know that all of the elements in the array are between 0 to n-1. The function is supposed to return 0 if there is a missing number in the range (0 to n-1). Otherwise, it returns 1. As you can understand, duplicates are possible. The thing is that its supposed to run on O(n) runtime.
I think I managed to do it but i'm not sure. From looking at older posts here, it seems almost impossible and the algorithm seems much more complicated then the algorithm I have. Therefore, something feels wrong to me.
I could not find an input that returns the wrong output yet thou.
In any case, I'd appreciate your feedback- or if you can think of an input that this might not work for. Here's the code:
int missingVal(int* a, int size)
{
int i, zero = 0;
for (i = 0; i < size; i++)
//We multiply the element of corresponding index by -1
a[abs(a[i])] *= -1;
for (i = 0; i < size; i++)
{
//If the element inside the corresponding index is positive it means it never got multiplied by -1
//hence doesn't exist in the array
if (a[i] > 0)
return 0;
//to handle the cases for zeros, we will count them
if (a[i] == 0)
zero++;
}
if (zero != 1)
return 0;
return 1;
}
Just copy the values to another array placing each value in its ordinal position. Then walk the copy to see if anything is missing.
your program works and it is in O(N), but it is quite complicated and worst it modify the initial array
can be just that :
int check(int* a, int size)
{
int * b = calloc(size, sizeof(int));
int i;
for (i = 0; i != size; ++i) {
b[a[i]] = 1;
}
for (i = 0; i != size; ++i) {
if (b[i] == 0) {
free(b);
return 0;
}
}
free(b);
return 1;
}
This problem is the same as finding out if your array has duplicates. Here's why
All the numbers in the array are between 0 and n-1
The array has a size of n
If there's a missing number in that range, that can only mean that another number took its place. Which means that the array must have a duplicate number
An algorithm in O(n) time & O(1) space
Iterate through your array
If the sign of the current number is positive, then make it negative
If you found a negative this means that you have a duplicate. Since all items are originally greater (or equal) than 0
Implementation
int missingVal(int arr[], int size)
{
// Increment all the numbers to avoid an array with only 0s
for (int i = 0; i < size; i++) arr[i]++;
for (int i = 0; i < size; i++)
{
if (arr[abs(arr[i])] >= 0)
arr[abs(arr[i])] = -arr[abs(arr[i])];
else
return 0;
}
return 1;
}
Edit
As Bruno mentioned if we have an array with all zeros, we could have run into a problem. This is why I included in this edit an incrementation of all the numbers.
While this add another "pass" into the algorithm, the solution is still in O(n) time & O(1) space
Edit #2
Another great suggestion from Bruno which optimizes this, is to look if there's more than one zero instead of incrementing the array.
If there's 2 or more, we can directly return 0 since we have found a duplicate (and by the same token that not all the numbers in the range are in the array)
To overcome the requirement that excludes any extra memory consumption, the posted algorithm changes the values inside the array by simply negating their value, but that would leave index 0 unchanged.
I propose a different mapping: from [0, size) to (-1 - size, -1], so that e.g. {0, 1, 2, 3, 4, ...} becomes {-1, -2, -3, -4, -5, ...}. Note that, for a two's complement representation of integers, INT_MIN = -INT_MAX - 1.
// The following assumes that every value inside the array is in [0, size-1)
int missingVal(int* a, int size) // OT: I find the name misleading
{
int i = 0;
for (; i < size; i++)
{
int *pos = a[i] < 0
? a + (-a[i] - 1) // A value can already have been changed...
: a + a[i];
if ( *pos < 0 ) // but if the pointed one is negative, there's a duplicate
break;
*pos = -1 - *pos;
}
return i == size; // Returns 1 if there are no duplicates
}
If needed, the original values could be restored, before returning, with a simple loop
if ( i != size ) {
for (int j = 0; j < size; ++j) {
if ( a[j] < 0 )
a[j] = -a[j] - 1;
}
} else { // I already know that ALL the values are changed
for (int j = 0; j < size; ++j)
a[j] = -a[j] - 1;
}

checking if a array has numbers in it from 0 to length -1 in C

I have got an assignment and i'll be glad if you can help me with one question
in this assignment, i have a question that goes like this:
write a function that receives an array and it's length.
the purpose of the function is to check if the array has all numbers from 0 to length-1, if it does the function will return 1 or 0 otherwise.The function can go through the array only one.
you cant sort the array or use a counting array in the function
i wrote the function that calculate the sum and the product of the array's values and indexes
int All_Num_Check(int *arr, int n)
{
int i, index_sum = 0, arr_sum = 0, index_multi = 1, arr_multi = 1;
for (i = 0; i < n; i++)
{
if (i != 0)
index_multi *= i;
if (arr[i] != 0)
arr_multi *= arr[i];
index_sum += i;
arr_sum += arr[i];
}
if ((index_sum == arr_sum) && (index_multi == arr_multi))
return 1;
return 0;
}
i.e: length = 5, arr={0,3,4,2,1} - that's a proper array
length = 5 , arr={0,3,3,4,2} - that's not proper array
unfortunately, this function doesnt work properly in all different cases of number variations.
i.e: length = 5 , {1,2,2,2,3}
thank you your help.
Checking the sum and product is not enough, as your counter-example demonstrates.
A simple solution would be to just sort the array and then check that at every position i, a[i] == i.
Edit: The original question was edited such that sorting is also prohibited. Assuming all the numbers are positive, the following solution "marks" numbers in the required range by negating the corresponding index.
If any array cell already contains a marked number, it means we have a duplicate.
int All_Num_Check(int *arr, int n) {
int i, j;
for (i = 0; i < n; i++) {
j = abs(arr[i]);
if ((j >= n) || (arr[j] < 0)) return 0;
arr[j] = -arr[j];
}
return 1;
}
I thought for a while, and then i realized that it is a highly contrained problem.
Things that are not allowed:
Use of counting array.
Use of sorting.
Use of more than one pass to the original array.
Hence, i came up with this approach of using XOR operation to determine the results.
a ^ a = 0
a^b^c = a^c^b.
Try this:
int main(int argc, char const *argv[])
{
int arr[5], i, n , temp = 0;
for(i=0;i<n; i++){
if( i == 0){
temp = arr[i]^i;
}
else{
temp = temp^(i^arr[i]);
}
}
if(temp == 0){
return 1;
}
else{
return 0;
}
}
To satisfy the condition mentioned in the problem, every number has to occour excatly once.
Now, as the number lies in the range [0,.. n-1], the looping variable will also have the same possible range.
Variable temp , is originally set to 0.
Now, if all the numbers appear in this way, then each number will appear excatly twice.
And XORing the same number twice results in 0.
So, if in the end, when the whole array is traversed and a zero is obtained, this means that the array contains all the numbers excatly once.
Otherwise, multiple copies of a number is present, hence, this won't evaluate to 0.

Using printf( ) in a for loop

When attempting this (code below), the console doesn't even request an input value, then spits out a random number (likely from a number previously stored at the location).
Why does this not work and how can i fix it?
int main( ) {
int arr[3];
for(int i = sizeof(arr); i <= 0; i--) {
scanf("%d", &arr[i]);
}
printf("%d", arr[2]);
return 0;
}
There are two things that are wrong.
Assuming you want the number of elements in the array, it is done, using:
size_t len = sizeof(arr) / sizeof(*arr)
sizeof gives the actual size (number of bytes allocated for arr.
You should start with len - 1 and not len.
NOTE: Array indexing is 0 based not 1 based, so the array elements are indexed from 0 to 2 But you would have tried to access arr[3], which can result in undefined behaviour.
You wrote i <= 0. So, i starts from let's say 2, is 2 <= 0 ? NO!
Hence it will never go inside the loop. The correct condition is i >= 0
int len = sizeof(arr) / sizeof(*arr);
for(int i = len - 1; i >= 0; i--)
Well, I don't know why you are taking reverse order input, but a general convention is to take input using:
size_t len = sizeof(arr)/sizeof(*arr);
for (i = 0; i < len; i++)
{
// take input
}
EDIT:
From other comments it seems that you don't understand the for loop.
Have a look in this answer
Please comment for any further clarification.
i <= 0
the code can never enter the loop since the initial value of i is greater than zero.
It is important to note that in C, other than languages like Java/Python, you must explicitly know the length of the array, sizeof will NOT give you the amount of items in the array.
int main() {
int arr[3];
int itemsInArray = 3;
for(int i = itemsInArray-1; i >= 0; i--) {
scanf("%d", &arr[i]);
}
printf("%d", arr[2]);
return 0;
};
Since i-- will decrease the value of i , and the condition for loop is i <=0 to start the loop the i must be 0 or negative.Since arr[3] will return 12(3 elements and each has 4 bytes(int has 4 bytes)), the value will be posivite,greater than 0 so we need to change the loop condition to check if i is positive
#include <stdio.h>
int main( ) {
int arr[3]={0};
int i = sizeof(arr)/sizeof(arr[0]) -1;
for(; i >= 0; i--) {
scanf("%d", &arr[i]);
}
printf("%d", arr[2]);
return 0;
}
There are a couple of issues with your code: first of all, sizeof(arr) won't return "3" as you probably thought; "arr" is a pointer to arr[0], so you are requesting the size of an int pointer.
Secondly, i <= 0 prevent the loop to even be executed.
Finally, please set array to zero while declarating, as best practice, ie:
int arr[3] = {0};
EDIT: i wrong-spelled my thoughts: you are requesting the size of the whole memory area allocated for the array.
Comments below are corrected though.

c loop stops when array value is zero not null

int findMax(int*sums){
int t = 0;
int max = sums[0];
while (sums[t] != '\0'){
printf("current max: %d %d\n", max, sums[t]);
if (sums[t] > max ){
max = sums[t];
}
t ++;
}
return max;
}
This outputs:
current max: 7 7
current max: 7 4
current max: 7 2
And its ignoring the rest of the list, sums. I think this is because the next element in sums is 0. But I can't see why it would treat 0 as '\0' (null).
sums is an array of integers (technically a pointer to integer). '\0' (the null byte) and 0 are the same value, so your loop will stop when it encounters a 0. There is no such thing as a null value as far as integers are concerned. The term "null" is used to refer to the value NULL, which is a pointer usually with the value 0 (i.e., a pointer that doesn't point to anything), and also the null (0) byte, such as the one that occurs at the end of a null-terminated string.
I do remember the time when I first encountered the same problem ( while I was trying to build a big number library using int arrays ), and eventually I figured out pretty much the same as what other answers say that technically '\0' and 0 have the same value.
Now here are 2 ways that I used to overcome this problem and these are only applicable under certain conditions
Case 1 :
Condition : When all your input elements are positive
Now since all your input elements are positive, you can mark the end of the array by inserting a negative number
Typically, I use -1, this way :
int a[] = {1, 2, 3, 4, -1}
for(int index = 0; a[index] != -1; index++)
{
//use the array element a[index] for desired purpose!
}
Instead you can enter any negative number and do it this way
for(int index = 0; a[index] >= 0; index++)
{
//use the array element a[index] for desired purpose!
}
Case 2 :
Condition : When all your elements are bound within a certain range
You might have got the idea by now :), lets say that all your elements belong to the range [-100,100]
you can insert any number above or below the bounds of the range to mark the end... so in the above case I can mark the end by entering a number < -100 and >100.
And you can iterate the loop this way :
for(int index = 0; (a[index] > -100) && (a[index] < 100); index++)
{
//use the array element a[index] for desired purpose!
}
Generalizing both the cases, just place a value at the end of array which you know for sure is not equal to an array element
for(int index = 0; a[index] != value_not_in_array; index++)
{
//use the array element a[index] for desired purpose!
}
So, now under Case 1, your while loop condition can be either of the following :
while(sums[t] != -1) //typically ended with `-1`
//(or)
while (sums[t] >= 0) //ended with any negative number
And under Case 2 :
while ((sums[t] >min_range) && (sums[t] < max_range)) // when elements are bound within a range
Or more generally :
while( sums[t] != value_not_in_array )
The underlying fact of both the cases is that I'm finding out a
potential replacement for terminating '\0' character.
Hope this helps, happy coding ;)
'\0' is a representation of a non-printable ASCII character. Specifically, it is the character 0 (as in, the zeroeth character, not the character '0', whichis 48. Look it up on an ASCII table).
'\0' is the same as 0 the same way 'A' is == 65. There is no difference as far as the compiler is concerned. '\0' == 0 will always evaluate as true.
Note that only strings are terminated with a '\0', unlike all other arrays.
In C, the character literal '\0' has the value (int)0, that's what the escape sequence translates to.
#include <stdio.h>
int main() {
int i = 0;
char c = '\0';
printf("%s\n", (i == c) ? "same" : "different");
}
http://ideone.com/sYRbYZ
I think you're confusing a pointer check for NULL vs a value check for zero.
Here are two slightly different variants of your function to illustrate the point:
#include <stdio.h>
int
findPtr(int **sums)
{
int t = 0;
int max = *sums[0];
int val;
while (sums[t] != NULL) {
val = *sums[t];
printf("current max: %d %d\n", max, val);
if (val > max) {
max = val;
}
t++;
}
return max;
}
int
findArr(int *sums,int count)
{
int t = 0;
int max = sums[0];
while (t < count) {
printf("current max: %d %d\n", max, sums[t]);
if (sums[t] > max) {
max = sums[t];
}
t++;
}
return max;
}
Since zero (either 0 or \0--which are equivalent) is a valid value in sums, it can't be used as a sentinel for end of array as your check was doing. You'll need to pass down the array count as in the latter example.
In your code, you are taking a pointer to an array of integers as input in the findMax function. '\0' is a character. You are comparing integers to a character, causing the compiler to cast the character '\0' and use its integer equivalent NULL (or simply 0). Therefore the program stops when it comes to a 0 in the array.
You might want to try :
int findMax(int*sums,int arraysize)
{
int t=0;
int max = sums[t];
while(t<arraysize)
{
printf("current max: %d %d\n", max, sums[t]);
if (sums[t] > max )
{max = sums[t];}
t++;
}
return max;
}

Finding an element repeating n times in 2n size array. Will this solution work?

I have an array which has 2n elements where n elements are same and remaining n elements are all different. There are lot of other complex algorithms to solve this problem.
Question: Does this approach give the same result or I am wrong somewhere?
#include<stdio.h>
main()
{
int arr[10],i,res,count=0;
printf("Enter the array elements:\t");
for(i=0;i<10;i++)
scanf("%d",&arr[i]);
for(i=0;i<8;i++)
{
if(arr[i]==arr[i+1] || arr[i]==arr[i+2])
{
res=arr[i];
break;
}
else if(arr[i+1]==arr[i+2])
{
res=arr[i+1];
break;
}
}
for(i=0;i<10;i++)
if(arr[i]==res)
count++;
if(count==5)
printf("true, no. repeated is:\t%d",res);
else printf("false");
return 0;
}
In addition to failing for the trivial 2 element case, it also fails for 4 elements in this case:
a b c a
I think the easiest way to solve this problem is to solve the majority element problem on a[1] ... a[2*N-1], and if no majority is found, then it must be a[0] if a solution exists at all.
One solution to the majority element problem is to scan through the array counting up a counter whenever the majority candidate element is encountered, and counting down the counter when a number different from the candidate is encountered. When the counter is 0, the next element is automatically considered the new candidate.
If the counter is positive at the end of the scan, the candidate is checked with another scan over the array. If the counter is 0, or the second scan fails, there is no majority element.
int majority (int a[], int sz) {
int i, count1 = 0, count2 = 0;
int candidate = -1;
for (i = 0; i < sz; ++i) {
if (count1 == 0) candidate = i;
count1 += ((a[candidate] == a[i]) ? 1 : -1);
}
if (count1 > 0) {
for (i = 0; i < sz; ++i)
count2 += (a[candidate] == a[i]);
}
if (count2 <= sz/2) candidate = -1;
return candidate;
}
Your algorithm will fail when the array has only 2 elements. It does not handle trivial case

Resources