int i in a for loop vs not - c

Why would the following not work when i is defined in the for loop
#include <stdio.h>
#include <math.h>
int N;
long long int H() {
long long int ans=0;
int i, lt;
if(N <= 0)
return 0;
for(i=1, lt=sqrt(N); i<=lt; i+=1) /* if i=1 is replaced by int i=1 => garbage */
ans+=(N/i);
ans = 2*ans-(lt*lt);
return ans;
}
int main() {
scanf("%d",&N);
printf("%lld\n",H());
return 0;
}
output when it's defined at the top
Input: 8
Output: 20
output when it's defined in the for loop /* for (int i=1 ..) */
Input: 8
Output: 1243068212
I see that I get a warning lt is initialized when used here, why?

When you write this:
int lt;
for (int i=1, lt=sqrt(N); ...)
That defines two new inner variables named i and lt; in particular, the new lt variable shadows the outer one, making it temporarily inaccessible within the inner scope. So, the outer lt variable never gets initialized, and when you compute ans = 2*ans-(lt*lt), it's using that uninitialized value to compute the result.

One good pattern to look for when starting coding in C is variables with values WAY out of bounds of what they should be.
So in your case you were expecting 20 and instead got 1243068212, this implies that the variable was not initiated properly and thus it's value is an undefined piece of memory (Correct me if I'm wrong).
Here's a good article on initialization - http://publications.gbdirect.co.uk/c_book/chapter6/initialization.html

Related

Why does declaring variables on a single line give an unexpected result?

I programmed a simple clock and found that while hours and seconds are okay, minutes are not if I declare the variables on a single line (minutes starts at 16 and not at 0 as expected).
The problem is solved if I declare the variables on separated lines. I'm still curious though, anybody knows why?
Here's the code:
#include <stdio.h>
#include <windows.h>
//h=hours, m=minutes, s=seconds.
int main(){
int h, m, s = 0; //THIS IS THE LINE: WHY "m" STARTS AT 16 AND NOT 0?
int delay = 1000;
while(1){
s++;
if(s>59){
m++;
s=0;
}
if(m>59){
h++;
m=0;
}
if(h>12){
h=1;
}
printf("\n %02d:%02d:%02d", h, m, s);
Sleep(delay);
system("cls");
}
}
Your variables are uninitialized - they can take any value, and using them before initialization is (usually) indeterminate behavior.
A line of code like:
int h, m, s = 0;
does not define each variable to be zero - only the third one. It is equivalent to:
int h;
int m;
int s = 0;
To fix, initialize all of your variables as zero:
int h = 0, m = 0, s = 0;
You haven’t initialized h or m, so their initial values might whatever was in that memory already, or something else entirely. C does not automatically initialize variables to 0.
When you declare multiple variables on one line, the value only applies to the variable it comes after. So
int a, b, c = 5;
only sets c to 5, while
int a = 1, b = 2, c = 3;
initializes all of them. In your case, you just need to use
int h = 0, m = 0, s = 0;
You compiler likely has an option for warnings (-Wall in gcc), which should warn you about using an uninitialized variable.
int h, m, s = 0; // THIS IS THE LINE: WHY "m" STARTS AT 16 AND NOT 0?
Well, I guess, because C is not English. The "= 0" part applies just to that one variable name s, not to the whole line.
Although, you know, English doesn't necessarily apply modifiers to the whole line, either. If I say "There were three people standing on the streetcorner: A man, a woman, and a boy named Brad", you would not infer that the man and the woman were named Brad, too, would you?
[Footnote: Now I've got that old song "Me and you and a dog named Boo" stuck in my head. :-) ]

My function will give correct answers on only one call but not on multiple

I'm making a code for converting Decimal numbers to Binary(university assignment). If I only do DecToBinary(5) it gives me 101, and if I only do DecToBinary(6) it gives me 110, but when i do both of these statements in main() it gives me 101110101 when it should just give me 101110(joining the two answers above). I don't understand what is going on since it should just call DecToBinary(5) and print 101 then (without adding a newline character) call DecToBinary(6) and print 110.
void DecToBinary(int dec){
int temp[64]; //64 is just a max value
int i,j;
while(dec>0){
temp[i]=dec%2;
dec=dec/2;
i++;
}
for(j=0;j<i;j++){
printf("%d",temp[i-1-j]);
}
}
You haven't initialized the variable i. This means that the behaviour of your program is undefined, as the value of i may be different of 0 which is what you want.
To correct it, you just have to initialize i when declaring it, meaning int i = 0
The variable i is not initialized
int i,j;
so the function has undefined behavior.
You need to initialize it before the while loop.
Also the while loop should be substituted for a do-while loop. Otherwise the value 0 will not be processed correctly. For example
i = 0;
do
{
temp[i++] = dec % 2;
} while( dec /= 2 );
Also as the function does not process negative numbers then its parameter should have the type unsigned int
void DecToBinary( unsigned int dec )
Always initliaze variable. Check i and j in your case.

Why did the compiler assign different memory address to the same variable, after re-defining the variable?

The code is as follows:
#include <stdio.h>
int main()
{
int i;
printf("%p\n",&i);
for (i = 0; i < 5; i++)
{
int i = 10;
printf("%d %p\n", i,&i);
i++;
}
return 0;
}
First we defined a variable i (just after main). Then at the start of for loop we defined the same variable i again. So, inside for loop, value of i is 10. The for loop must iterate only once, since i>5 after first iteration. But to my surprise the output is as follows:
0x7ffe8b799da0
10 0x7ffe8b799da4
10 0x7ffe8b799da4
10 0x7ffe8b799da4
10 0x7ffe8b799da4
10 0x7ffe8b799da4
My questions are:
1) Why is the compiler considering the initial defined variable i while executing i<5;i++ instruction and, not the re-defined variable i? (after first iteration).
2) Why did compiler assign different memory address to same variable identifier i?
Why is the compiler considering the initial defined variable i while
executing i<5;i++ instruction and, not the re-defined variable i?
(after first iteration).
Because the re-defined (shadowing) variable isn't in scope yet. If you remove the first definition, you get an "identifier undeclared" error. This also doesn't change after the first iteration of the loop as it is determined at compile time.
2) Why did compiler assign different memory address to same variable
identifier i?
Even though you can't access the outer int i inside the loop as the second one shadows it, it still exists and therefore needs its own memory. It's not overwritten by the other int i. You can see that by putting a printf("%d\n", i); after the loop - it will print 5, because that's the value of that i after loop.
On another note, the i++; at the end of the loop has no effect because it affects the i inside the loop, which goes out of scope right after the i++;. This is unlike the i++; in the for (i = 0; i < 5; i++), which increases the outer i.
You've got two different variables both named i, so obviously the situation is going to be confusing! For every i in the program, we have to ask: is this the "outer" i, or the "inner" i?
Here's your program again, with the variables renamed for clarity:
#include <stdio.h>
int main()
{
int i1;
printf("%p\n",&i1);
for (i1 = 0; i1 < 5; i1++)
{
int i2 = 10;
printf("%d %p\n", i2,&i2);
i2++;
}
return 0;
}
To your specific question, the reason the loop runs 5 times is that the loop control for (i = 0; i < 5; i++) is unquestionably using the outer i.

C program to find the n'th prime number-

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int prime(long long int);
long long int *arr; //array to hold n prime numbers
int main()
{
int i,count=4;;
long long int n;
scanf("%lli",&n);
arr=malloc(sizeof(long long int)*n);
arr[0]=2;
arr[1]=3;
arr[2]=5;
arr[3]=7;
if (n==1) printf("%lli",arr[0]);
else{ if (n==2) printf("%lli",arr[1]);
else{ if (n==3) printf("%lli",arr[2]);
else{ if (n==4) printf("%lli",arr[3]);
else
{
for(i=2;count<n;i++)
{
if(prime(6*i-1)) { /*As prime nos are always 6k+1 or
arr[count]=6*i-1; 6k-1fork>=2 I checked only for those*/
count++; }
if(prime(6*i+1)&&count<=n) {
arr[count]=6*i+1;
count++; }
}
printf("%lli",arr[count]);
}}}}
//free(arr);
return 0;
}
int prime(long long int x)
{
int j=1,flag=1;
while(arr[j]<=sqrt(x))
{
if (x%arr[j]==0)
{
flag=0;
break;
}
j++;
}
return flag;
}
The code is working only for n=1,2,3,4, i.e i=0,1,2,3 for which the values are explicitly given. For n=5 onwards it is giving 0 as O/P
There is some glitch related to the global dynamic array as free(arr) is giving core dump error.
Q: Is this the right way to declare a global dynamic array? What could be the problem in this code?
Thank You in advance.
If that is your actual code you have 4 bugs:
2 line comment scopes out a line of your code
the second if should check count < n not count <= n as if count == n you cannot write to arr[count]
You cannot print arr[count] only arr[count-1] which is probably what you mean
In the case where n is less than 4 you still set arr[1], arr[2] and arr[3] which may be out of bounds
It is of course also inefficient to call sqrt(x) in every loop iteration, potentially you should call it outside and there may be a potential rounding issue bug due to the way square roots are calculated, so you might prefer:
while( arr[j] * arr[j] < x )
It would be preferable not to make this global and to pass it into your function.
It would also be preferable to move the main loop logic of your program outside of main().
I'm surprised you say you program works for n=1, 2 and 3 as it looks like you are setting out of bounds.
Your counter goes beyond the size of the array. Specifically both conditions (6i-1 and 6i+1) are met for i=2, and therefore counter is incremented twice, resulting in using arr[5] where you only allocated 5 places in the array. This is because you check counter<=n and not counter
Not sure this could be also be the reason for free creating a core dump, but it is possible (because once corrupting the memory, free may access corrupted data).

Variable Scope in C programming

In c, when this block of code is run,it outputs 10 10 10 10 10. I think the loop should exit after 1st execution as i becomes 11 but it is not happening. Why it is so?
#include<stdio.h>
int main()
{
int i;
for(i=0;i<5;i++)
{
int i=10;
printf("%d\t",i);
i++;
}
return;
}
But when program is written as below the output is similar to what i am thinking(i.e.10 ).What is the exact difference between above code and the code shown below? How C is handling these variable? I would be glad if anyone explain about this.
#include<stdio.h>
int main()
{
int i;
for(i=0;i<5;i++)
{
i=10;
printf("%d\t",i);
i++;
}
return;
}
In your first program, for loop is using the i declared outside the for to control the loop. The printf uses the i declared inside the for loop to print the value and this i has block scope.
The new declaration of i in the for loop temporarily hides the old declaration. Now the value of i is 10. At the end of the for loop block the new i is not visible to the program and the variable regains its old meaning and this time i stores the value as per the iteration of loop (either 1, 2, 3 or 4).
In the first code you declare your variable twice: one outside the loop and the second one inside the loop. So inside the loop compiler found another declaration for the variable so it uses the inner declaration (this called block scope).
So that the first program print 10 10 10 10 10 because this is the inner declaration int i=10
But in the second code you declare it once so the compiler use this declaration in the whole program.
In C99 or later, you can write this variation on your code with 3 independent variables called i:
#include <stdio.h>
int main(void)
{
int i = 19;
printf("i0 = %d\n", i);
for (int i = 0; i < 5; i++)
{
printf("i1 = %d\n", i);
int i = 10;
printf("i2 = %d\n", i);
i++;
}
printf("i0 = %d\n", i);
return 0;
}
The output is:
i0 = 19
i1 = 0
i2 = 10
i1 = 1
i2 = 10
i1 = 2
i2 = 10
i1 = 3
i2 = 10
i1 = 4
i2 = 10
i0 = 19
(In C89, you can't have the variable tagged i1 in the output, and you couldn't demonstrate the two variables in the loop because declarations have to precede statements such as printf() calls.)
Because in first example the i inside the loop is not the same as the one which governs/controls the loop, it is a completely different variable though with same name.

Resources