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

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. :-) ]

Related

While-loop not breaking when extra 'int' keyword added?

I was doing some exercises on codewars, and had to make a digital_root function (recursively add all digits of a number together, up untill there's only one digit left).
I was fairly confident that I did it right, but for some reason my while-loop never broke, even though my prints showed that len was 1.
#include <stdio.h>
#include <string.h>
int digital_root(int n) {
char number[10];
sprintf(number, "%d", n);
int len = strlen(number);
printf("Outer print: %s %d %d\n", number, n, len);
int sum = 0;
while(len > 1)
{
sum = 0;
for(int i = 0; i<len; i++)
{
sum += number[i] - '0';
}
sprintf(number, "%d", sum);
int len = strlen(getal); //!!!
printf("Inner print: %s %d %d\n", number, sum, len);
}
return sum;
}
It took me a long time to figure out what was wrong. I noticed that I copy pasted the 'int' keyword when I recalculated the len in the while loop (line marked with !!!). When I removed that (because it was not needed to redefine it as an int, it already was), everything suddenly worked like it was supposed to.
This kinda confused me. Why would this matter? I understand that redefining it is bad practice, but I don't get how this would result in the while-loop not breaking?
The used compiler is Clan3.6/C11.
(Ps. When I tried the same code in TIO, it worked in both cases...)
You're not redefining an existing variable, you're defining a new variable.
Consider this example:
#include <stdio.h>
int main(void) {
int x = 42;
printf("Outside, start. x (%p) = %d\n", (void *)&x, x);
{
printf("Inner block, start. x (%p) = %d\n", (void *)&x, x);
int x = 123;
printf("Inner block, end. x (%p) = %d\n", (void *)&x, x);
}
printf("Outside, end. x (%p) = %d\n", (void *)&x, x);
return 0;
}
Sample output:
Outside, start. x (0x7ffd6e6b8abc) = 42
Inner block, start. x (0x7ffd6e6b8abc) = 42
Inner block, end. x (0x7ffd6e6b8ab8) = 123
Outside, end. x (0x7ffd6e6b8abc) = 42
[Live demo]
This program outputs the memory address and value of x. Most uses of x refer to the outer variable declared at the beginning of main. But within the inner block, after int x = 123;, all occurrences of x refer to a second, separate variable that happens to also be called x (but is otherwise independent).
When execution leaves the inner block, the outer x variable becomes visible again.
This is also referred to as shadowing.
In your code, the outer len is never modified, so while(len > 1) is always true.
By the way, shadowing is a very common concept in most languages that support block scoping:
Perl
JavaScript
Haskell
Common Lisp
Your second int len creates a second, parallel, variable that goes away at the end of the {} block. The original len then returns to life, completely unchanged. Without the second int the original variable is changed. With it the original len is effectively an unchanged constant and infinite loop.

C - not entering if even when he should

I'm seriously mad right now. I need to compare one string with second, when chars from second string can somehow create first string. Example
foo1 = bill
foo2 = boril
foo2 can create foo1, because it contains all the letters from foo1.
So there's my program:
secret = religion
lettersGuessed = religonvpst
for(i = 0; i < lenSecret; i++){
for(l = 0; l < lenGuessed; l++)
printf("A: %c, B: %c, C: %d\n", secret[i], lettersGuessed[l], count);
if(secret[i] == lettersGuessed[l]){
printf("HI\n");
count++;
break;
}
printf("C: %d\n", count);
}
But variable count always stays at 0. This is output from console:
http://pastebin.com/YrHiNLNi
As you can see right from beginning, when secret[i] == lettersGuessed[l] in if should return true(1), it returns false(0). What's wrong with this? Why it's not working?
It's because you don't have curly braces after your second for loop. If you don't wrap the block of code you want to iterate over with curly braces, only the code before the first semi-colon encountered will be executed. In this case, your second loop will iterate over the printf statement but nothing else. So variable l will always be equal to lenGuessed when the if statement is executed and no letter from the first word matches the last letter of the second word, therefore count is never incremented.
Ok, this is totaly crazy.
Code that I posted in my question was of course wrong, because I forget braces of second for loop. Small, but fatal mistake, I know, but I was seriously mad so I didn't pay attention. Anyway, the original code is following:
int isWordGuessed(char secret[], char lettersGuessed[]){
int i, l, count = 0;
int lenSecret = strlen(secret);
int lenGuessed = strlen(lettersGuessed);
for(i = 0; i < lenSecret; i++)
for(l = 0; l < lenGuessed; l++)
if(secret[i] == lettersGuessed[l]){
count++;
break;
}
return lenSecret == count ? 1 : 0;
}
At first, it was returning 0. After compiling it with different tools and launching it on two different OS (Windows 7 64-bit and Windows XP 32-bit) i was finaly able to get 1 from that function.
It seems like variable count had non-zero value while launching, so instead of int i, l, count; I wrote int i, l, count = 0;
Well, now I don't understand only one thing - why sometimes variables has non-zero value even when I never touched them. It happened to my before, but only in C, in other languages I never had such a problem.

Variable being used without being initialized? C Language

I can't quite figure out what my issue is here. I keep getting an error in my code.
Error: Run-Time Check Failure: Variable used without being initialized.
: warning C4700: uninitialized local variable 'b' used
can someone help me solve this problem ? Any help would be appreciated.I'm using visual studio as a compiler for C and I'm a beginner in it and this is a one of the assignment. I don't see why i keep getting this issue if i input "int b;" in the beginning of the program. Wouldn't that variable be initialized?
Here is the code:
#include <stdio.h>
//Create a program that asks the user to enter a number until the user enters a -1 to stop
int main()
{
int b;
//as long as the number is not -1, print the number on the screen
while(b!=-1) {
printf("Hello there! would you please enter a number?");
scanf(" %d",&b);
//as long as the number is not -1, print the number on the screen
if(b!=-1){
printf("Thank you for your time and consideration but the following %d you entered wasn't quite what we expected. Can you please enter another?\n",b);
//When the user enters a -1 print the message “Have a Nice Day :)” and end the program
}else {
printf("Have a Nice Day :), and see you soon\n");
}
}
return 0;
}
When you declare a variable, such as you have:
int b;
It is not initialised to have any value, it's value is unknown until you initialise it.
To fix this error, replace
int b;
With
int b = 0;
Error is here:
int main()
{
int b;
//as long as the number is not -1, print the number on the screen
while(b!=-1) {
Since you haven't initialized b, it can be anything. You then use it as a condition for while loop. This is very dangerous.
It may be that system randomly assign value of -1 ( its a rare possibility ) to it .. in that case your while loop will not be actioned
Intialize b to some value
For eg do this:
int b = 0;
You're doing:
int b;
and then doing:
while(b!=-1) {
without ever initializing b. The problem is exactly what your warning is telling you it is.
C does not automatically initialize local variables for you, the programmer has to take care of that. int b allocates memory for your variable, but doesn't put a value in there, and it will contain whatever garbage value was in that memory prior to allocation. Your variable won't be initialized until you explicit assign, or another function explicitly assigns, a value to it.
int b;
is a variable declaration. Explicitly, the value is not initialized. The compiler will emit instructions for the program to reserve space to store an integer at a later time.
int b = 1;
this is a variable declaration with initialization.
int b;
while (b != -1)
this is use of an uninitialized variable, but so is
int a = rand() % 3; // so 'a' can be 0, 1 and or 2.
int b;
if (a == 0)
b = 1;
else if (a == 1)
b = 2;
printf("b = %d\n", b);
this is also a potential cause of uninitialized use of b. If 'a' is 2, we never assign a default value to b.
Upshot is you should always try to specify the default value with the declaration. If the logic that will determine initialization is complex, consider using an out-of-bounds value, as you are using -1.
Can you spot the bug in the following?
int b = -1;
if (a == 0)
b = 1;
else if (a == 1)
b = 2;
else if (a > 2)
b = 3;
if (b == -1) {
// this is an error, handle it.
}

int i in a for loop vs not

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

Strange output from simple C program to find the largest continuous subarray in an array

I am very new to C, and I was just playing around and seeing if I could recreate a simple subarray adding program (finds the largest continuous subarray in an array). I ran in to an odd issue where if I defined n as an integer and used it as a condition in my for loop I would get absolute junk back.
Forgive this weird code, I pretty much just copied and pasted a file I was monkeying around with (lots of extra printfs etc). If I run this, I get an output of "4196053", or something similar to that, for each printf call in the for loop. Even in the first printf call (before entering the loop) it seems to be messed up.
#include <stdio.h>
int maxI (int a, int b)
{
int max = (a >= b) ? a : b;
return max;
}
int main (void)
{
int array[] = { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
int n = 11;
int maxSoFar, i = 0;
int maxHere = 0;
printf ("%i\n", maxSoFar); //why is it screwing up here?
for (i = 0; i < n; i++) {
printf ("%i\n", maxSoFar);
maxHere = maxI(maxHere + array[i], 0);
maxSoFar = maxI(maxSoFar, maxHere);
}
printf ("The max is %i.\n", maxSoFar);
return 0;
}
If I just use 11 in the conditional instead of a variable it works fine. Anyone know what is going on here?
maxSoFar is having some arbitrary data, so you need to initialize it first
int maxSoFar = 0, i = 0;
^^Initialize to zero
Your error is here
int maxSoFar, i = 0
You never declared maxSoFar so it's using garbage data.
Initialize it to 0, and you should be good.
It gives you a garbage value because you never initialize maxSoFar. This means that it will have the value of whatever was left in memory at that point.
You main issue is that maxSoFar is a local(automatic) variable and is therefore if it is not initialized it will have an indeterminate value, so the results of this program are also indeterminate. The fix would be to properly initialize maxSoFar, probably to the first element of array.
For completeness sake, the relevant section of the C99 draft standard is 6.7.8 Initialization paragraph 10 which says:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate.[...]

Resources