c loop stops when array value is zero not null - c

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;
}

Related

The output is weird on my C Console App. Any ideas?

I want to make an app that determines whether the given input is a positive number, and then prints them out if there are more than 2 positive numbers, but there is a weird output which I've been trying to fix for a few hours.
Note : I'm somewhat of a beginner in C.
#include <stdio.h>
int main() {
const char arr[][20] = {"First Number : ", "Second Number : ", "Third Number : "};
int numbers[2]; // number list
int posNumbers[2]; // positive number list
int n = 0; // n for itinerating posNUmbers
for ( int i = 0 ; i <= 2; i++) {
printf("%s", arr[i]);
scanf("%i", &numbers[i]);
} // puts input in array
for ( int i = 0 ; i <= sizeof(numbers) / sizeof(numbers[0]) + 1 ; i++ ) {
if (numbers[i] > 0) {
posNumbers[n + 1] = numbers[i];
}
} // adds positive in array
if (sizeof(posNumbers) / sizeof(posNumbers[0]) + 1 > 1) {
printf("There are atleast 2 pos numbers, which are : \n");
for ( int i = 0; i <= sizeof(posNumbers) / sizeof(posNumbers[0]) + 1 ; i++) {
printf("%i", posNumbers[i]);
}
} else {
printf("THere are not enough positive numbers.");
}
}
Output : There are atleast 2 pos numbers, which are : 4419368778941968054388
You have several misconceptions about arrays and the use of sizeof that cause you to attempt to access values beyond the end of your numbers and posNumbers arrays that invokes Undefined Behavior1 in your code. You further invoke Undefined Behavior when you attempt to read from uninitialized elements in the posNumbers array.
In C, arrays are:
zero based. Meaning that an array of nelem elements has valid indexes of 0 <= index < nelem,
when looping over all elements in an array, you loop from i = 0; i < nelem; i++,
if you fail to initialize your arrays all zero and do not fill all elements and attempt to loop over all elements in your array, you invoke Undefined Behavior when you attempt to access the uninitialized element (lesson -- initialize all arrays to begin with),
when you use sizeof array / sizeof array[0], you get the total number of elements in the array, not the number of elements filled,
your loop over posNumbers ignores the fact that less than all elements can be filled invoking Undefined Behavior if you attempt to read from an uninitialized element of the array,
when filling less than all values in an array, simply keep a counter to track the number of elements filled, you have n declared already.
Additional points to consider:
avoid using MagicNumbers in your code and instead #define a constant. This helps avoid the problems you are having with 2,
above all learn you cannot use scanf() (or any user input function) correctly unless you check the return, especially where numeric conversions are involved. What if the user enters "four" instead of 4?
Putting it altogether, and making a few additional changes to your output calls, you can rewrite your code to avoid the problems above as:
#include <stdio.h>
#define NVALS 3 /* if you need a constant, #define one (or more) */
int main (void) {
/* an array of pointers to the string-literals is fine */
const char *arr[] = { "First Number : ",
"Second Number : ",
"Third Number : " };
int numbers[NVALS] = {0}, /* initialize all arrays */
posNumbers[NVALS] = {0},
n = 0;
/* loop NVALS times reading number input */
for (int i = 0 ; i < NVALS; i++) {
/* no conversion involved, fputs is fine for end-of-line control */
fputs (arr[i], stdout);
/* you can't use scanf correctly unless you CHECK THE RETURN
* to validate each conversion was successfully completed
*/
if (scanf("%i", &numbers[i]) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
/* compare if numbers[i] positive */
if (numbers[i] > 0) {
posNumbers[n++] = numbers[i];
}
}
if (n > 1) { /* check if at least two numbers positive */
puts ("\nThere are atleast 2 pos numbers, which are :");
for (int i = 0; i < n; i++) {
printf ("%i\n", posNumbers[i]);
}
}
else {
puts ("\nMust have at least two positive numbers.");
}
}
(note: a good compiler will convert printf ("const string"); to fputs ("const string", stdout); for you, but choosing fputs() over the variadic printf() when there are no conversions involved indicates you understand how to choose the proper tool for the job on your own)
Example Use/Output
If less than two positive integers:
$ ./bin/threeposnumbers
First Number : -10
Second Number : 0
Third Number : 4
Must have at least two positive numbers.
If the two positive numbers are provided:
$ /bin/threeposnumbers
First Number : -10
Second Number : 2
Third Number : 4
There are atleast 2 pos numbers, which are :
2
4
If all positive numbers are provided:
$ ./bin/threeposnumbers
First Number : 10
Second Number : 2
Third Number : 4
There are atleast 2 pos numbers, which are :
10
2
4
(if you are old enough, you will recall the special significance of those numbers for a specific soft-drink marketing campaign, hint: initials DP :)
Handling non-integer input:
$ ./bin/threeposnumbers
First Number : -10
Second Number : two
error: invalid integer input.
Let me know if you have further questions.
footnotes:
1.) See:
Undefined, unspecified and implementation-defined behavior and
What is indeterminate behavior in C++ ? How is it different from undefined behavior? and
Undefined behavior
You say you want to store 3 numbers but you are declaring your array size to be 2. If you want to store 3 numbers this code:
int numbers[2]; // number list
int posNumbers[2]; // positive number list
Should be
int numbers[3]; // number list
int posNumbers[3]; // positive number list
You are supposed to declare the array sizes as how big as you want them but you can only use up to size - 1 since indexes start from 0.
Also you should probably fix the things that #WeatherVane is stating in the comments.
Addendum on the answers: you can interleave then in a struct to make it clearer which variables go together. This can also reduce the number of times you repeat yourself.
You have: a) a fixed number of numbers to enter, and b) you are going to copy all the positive numbers to a second, possibly smaller, array. The simplest is to make an equal-size array and explicitly have the size. I would refactor the code as such,
#include <stdio.h>
int main(void) {
struct {
const char *title;
int number;
} arr[] = { { "First", 0 }, { "Second", 0 }, { "Third", 0 } };
struct {
size_t size;
int number[sizeof arr / sizeof *arr];
} positives;
const int arr_size = sizeof arr / sizeof arr[0];
// enter numbers
for ( size_t i = 0 ; i < arr_size; i++) {
printf("%s Number : ", arr[i].title);
if(scanf("%i", &arr[i].number) != 1) return 1;
}
// adds positive in array
positives.size = 0;
for ( size_t i = 0 ; i < arr_size ; i++ ) {
if (arr[i].number > 0) {
// bounded by arr_size
positives.number[positives.size++] = arr[i].number;
}
}
if (positives.size >= 2) {
printf("There are atleast 2 pos numbers, which are : \n");
for ( size_t i = 0; i < positives.size ; i++) {
printf("%i\n", positives.number[i]);
}
} else {
printf("THere are not enough positive numbers.\n");
}
}

C: Printing INT Values on array - How to stop printing on NULL values?

I need to print values stored in an int array, stopping when a NULL character is encountered ('\0').
So I have this code:
const int display[10] = {1,4,8,2,0,9,2};
int main(){
int i = 0;
for (i = 0; i < 10; i++){
if (display[i] == '\0'){
break;
}
printf("%d\n", display[i]);
}
exit(0);
}
I expected to print all the values of display[10] OR break when a '\0' was encountered but my code breaks on display[4] (0) instead of continuing until display[6].
Any advice on how to achieve this, avoiding printing the null characters at the end of my array?
The null character, '\0', is equal to 0. That's why your loop is only printing the first four elements. It breaks when it encounters 0.
In C, '\0'==0. If you want to print only the initialized fields, put a sentinel (say, a negative number) right after the last initialized field and break the loop when you either encounter the sentinel or count to 10.
const int display[10] = {1,4,8,2,0,9,2,-1 /* a sentinel */};
for (i = 0; i < 10 && display[i] >= 0; i++) {
You do not need to check whether null is exist or not. First declare the array without total number initialization. Then You can just run the loop by checking the total number of array element. Now the question is how you get the number of element? It is easy.
const int arr[]= { 1, 2, 3};
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size; i++) {
printf("%d", arr[i]);
}

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.

Binary search accessing out of range index

This is the code:
char binarySearch(unsigned int target, int* primes, unsigned int size){
int* ptrToArray = primes;
unsigned int first = 0;
unsigned int last = size;
while (first <= last){
unsigned int middle = first + (last - first) / 2;
printf("first: %d, last: %d, middle: %d\n", first, last , middle);
if (ptrToArray[middle] == target){
return 1;
}
if (ptrToArray[middle] < target){
first = middle + 1;
}else{
last = middle - 1;
}
}
return 0;
}
This is the output:
I've been staring at that peace of code for more than one should and still can't figure out where is the flaw.
If middle is 0, as near the end of your debug output, the statement
last = middle - 1
causes an integer overflow; the conditions have to be reworked a bit.
You may get an out of bound when you are looking for an element not in the array, and is bigger than the array, due to allowing keep iteration when last and first equal each other in while (first <= last)
Think of what happens when you send an empty array: size == 0:
first = 0, last = 0, and thus: (first <= last) == true.
Then, middle = 0 + (0 - 0)/2 = 0, and next you access ptrToArray[0], which is out of bound.
The problem is that you define your index variables (first, last, middle) as unsigned int while in your logic, last can in fact become negative. However, in that case, since they're defined as unsigned and because of the way 2's complement representation of negative numbers works, the condition in your while loop is still true.
Take a look at the following example code for illustration:
#include <stdio.h>
int main() {
/* defining the variables as unsigned */
unsigned int first_u = 0;
unsigned int last_u = -1;
if (first_u <= last_u)
printf("less than\n");
else
printf("greater or equal\n");
/* defining the variables as signed */
int first_s = 0;
int last_s = -1;
if (first_s <= last_s)
printf("less than\n");
else
printf("greater or equal\n");
return 0;
}
Other than that, you should use either < in your while-condition or define the initial value of last as size-1. Otherwise, if you're searching for an element that is greater than the last element in your array, you will run out of bounds.
Firstly the negative value of middle is due to overflow (unsigned int).
Also I think you should have : unsigned int last = size-1 because if first becomes equal to last=size the you will use ptrToArray[middle] and middle=size so it will be out of array bounds. This will solve also the case of size =0 mentioned above .
Finally to make your code more easy to read you could write :
middle =(first+last)/2 which is the middle of [first,last] space, and equals to first+(last-first)/2 .

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

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
}

Resources