I am a beginner is Computer Science and I recently started learning the language C.
I was studying the for loop and in the book it was written that even if we replace the initialization;testing;incrementation statement of a for loop by any valid statement the compiler will not show any syntax error.
So now I run the following program:
#include<stdio.h>
int main()
{
int i;
int j;
for(i<4;j=5;j=0)
printf("%d",i);
return 0;
}
I have got the following output.
OUTPUT:
1616161616161616161616161616161616161616.........indefinitely
I understood why this is an indefinite loop but i am unable to understand why my PC is printing this specific output? Is there any way to understand in these above kind of programs what the system will provide us as output?
This is a case of undefined behaviour.
You have declared i so it has a memory address but haven't set the value so its value is just whatever was already in that memory address (in this case 16)
I'd guess if you ran the code multiple times (maybe with restarts between) the outputs would change.
Some more information on uninitialized variables and undefined behaviour: https://www.learncpp.com/cpp-tutorial/uninitialized-variables-and-undefined-behavior/
Looks like i was never initialized, and happens to contain 16, which the for loop is printing continuously. Note that printf does not add a new line automatically. Probably want to read the manual on how to use for.
To better understand what is going on, you can add additional debugging output to see what other variables are set to (don't forget the \n newline!) but really problem is the for loop doesn't seem right. Unless there's something going on with j that you aren't showing us, it really doesn't belong there at all.
You are defining the variable i but never initializing it, instead, you are defining the value for j but never using it.
On a for loop, first you initialize the control variable, if you haven't already done it. Then you specify the condition you use to know if you should run another iteration or not. And last but not least, change the value of the control variable so you won't have infinite loops.
An example:
#include <stdio.h>
int main()
{
// 1. we declare i as an integer starting from 1
// 2. we will keep iterating as long as i is smaller than 10
// 3. at the end of each iteration, we increment it's value by 1
for (int i = 1; i < 10; i++) {
printf("%d\n", i);
}
return 0;
}
#include <stdio.h>
int main(void) {
// single-line for-loop
for (int i = 0; i < 5; i--);
// delays to execute this syntax
printf("Hello\n");
return 0;
}
Why does it take around 10 seconds to print Hello in console after running it?
Notice that the use of a semicolon at the end of the For loop is intentionally given.
I've figured out how and why this happened..
It's because the range of int data type is from -2,147,483,648 to 2,147,483,647. "i" in this for loop is going from 0 to -2,147,483,648 (because of i--;) and after that when the value of "i" becomes 2,147,483,647 (because of limitations of data type's range and data overflow), hence making the condition (i<5;) false and the loop stops. After that the next statement (printf("Hello");) prints "Hello".
The whole process of the loop iterating 2 Billion times takes 10 seconds by my compiler to process and after that it prints the next call (which is printf("Hello");)
int i;
for(i=0;i<5;i--);
We don't know anything about your C implementation.
For more about the C language, see this reference and later the C11 standard n1570. Read also Modern C
My guess would be that you use a recent GCC compiler on a x86-64 computer. I recommend reading the documentation of your optimizing compiler, for GCC it is here. You could also need to read the documentation of your linker, so (on my Linux computer) of binutils.
If indeed that is the case, I recommend enabling all warning and debug info, so compile your code with gcc -Wall -Wextra -g. You are likely to get some warnings.
You are decrementing i. Assume that int are 32 bits. Then on the first loop, i is 0; on the second loop, i becomes -1 .... Your computer probably will loop 231 times. So about two billions loops.
Computers are fast, but not infinitely fast.
My recommendation: learn to use a debugger, such as GDB.
At last, <stdio.h> gives buffered input output. So learn to use fflush(3) and read of course the documentation of printf(3).
for(i=0;i<5;i--);
Well I don't know how you got Hello even after 10 seconds! Take a closer look at the for loop. It actually never ends because the i value is constantly decreasing and hence it will always be less than 5. So I suppose the process was terminated.
Now don't think that just because you added a semi colon after the for loop the for loop won't run. It will run. Looping will take place, its just that there is no code to execute. The semi colon will be considered as a null statement by the compiler. And once the condition will return false the compiler will move on to the next statement.
Please check whether the code is correct or not. I highly doubt that it is ++i and not --i
Since the decrement (i.e. i--) will be executed till infinity for i < 5 never meets, as soon as the iterating integer i reaches the minimum value that an integer could hold (i.e. -2,147,483,648) get overflowed and it instantly quits the loop at negative 2147483648-th iteration.
If you write something like this:
int i;
long long j = 0; // intentionally using to hold lesser than the value
// and integer could hold for debugging test
for(i = 0; i < 5; i--)
j = i;
printf("%d\n", j);
Then you'll get to know practically in which iteration the loop is quitting and the reason behind getting a few time to print Hello after that loop.
I have recently started to learn C and I am taking a class with C as the subject. I'm currently playing around with loops and I'm running into some odd behaviour which I don't know how to explain.
#include <stdio.h>
int main()
{
int array[10],i;
for (i = 0; i <=10 ; i++)
{
array[i]=0; /*code should never terminate*/
printf("test \n");
}
printf("%d \n", sizeof(array)/sizeof(int));
return 0;
}
On my laptop running Ubuntu 14.04, this code does not break. It runs to completion. On my school's computer running CentOS 6.6, it also runs fine. On Windows 8.1, the loop never terminates.
What's even more strange is that when I edit the condition of the for loop to: i <= 11, the code only terminates on my laptop running Ubuntu. It never terminates in CentOS and Windows.
Can anyone explain what's happening in the memory and why the different OSes running the same code give different outcomes?
EDIT: I know the for loop goes out of bounds. I'm doing it intentionally. I just can't figure out how the behaviour can be different across different OSes and computers.
On my laptop running Ubuntu 14.04, this code does not break it runs to completion. On my school's computer running CentOS 6.6, it also runs fine. On Windows 8.1, the loop never terminates.
What is more strange is when I edit the conditional of the for loop to: i <= 11, the code only terminates on my laptop running Ubuntu. CentOS and Windows never terminates.
You've just discovered memory stomping. You can read more about it here: What is a “memory stomp”?
When you allocate int array[10],i;, those variables go into memory (specifically, they're allocated on the stack, which is a block of memory associated with the function). array[] and i are probably adjacent to each other in memory. It seems that on Windows 8.1, i is located at array[10]. On CentOS, i is located at array[11]. And on Ubuntu, it's in neither spot (maybe it's at array[-1]?).
Try adding these debugging statements to your code. You should notice that on iteration 10 or 11, array[i] points at i.
#include <stdio.h>
int main()
{
int array[10],i;
printf ("array: %p, &i: %p\n", array, &i);
printf ("i is offset %d from array\n", &i - array);
for (i = 0; i <=11 ; i++)
{
printf ("%d: Writing 0 to address %p\n", i, &array[i]);
array[i]=0; /*code should never terminate*/
}
return 0;
}
The bug lies between these pieces of code:
int array[10],i;
for (i = 0; i <=10 ; i++)
array[i]=0;
Since array only has 10 elements, in the last iteration array[10] = 0; is a buffer overflow. Buffer overflows are UNDEFINED BEHAVIOR, which means they might format your hard drive or cause demons to fly out of your nose.
It is fairly common for all stack variables to be laid out adjacent to each other. If i is located where array[10] writes to, then the UB will reset i to 0, thus leading to the unterminated loop.
To fix, change the loop condition to i < 10.
In what should be the last run of the loop,you write to array[10], but there are only 10 elements in the array, numbered 0 through 9. The C language specification says that this is “undefined behavior”. What this means in practice is that your program will attempt to write to the int-sized piece of memory that lies immediately after array in memory. What happens then depends on what does, in fact, lie there, and this depends not only on the operating system but more so on the compiler, on the compiler options (such as optimization settings), on the processor architecture, on the surrounding code, etc. It could even vary from execution to execution, e.g. due to address space randomization (probably not on this toy example, but it does happen in real life). Some possibilities include:
The location wasn't used. The loop terminates normally.
The location was used for something which happened to have the value 0. The loop terminates normally.
The location contained the function's return address. The loop terminates normally, but then the program crashes because it tries to jump to the address 0.
The location contains the variable i. The loop never terminates because i restarts at 0.
The location contains some other variable. The loop terminates normally, but then “interesting” things happen.
The location is an invalid memory address, e.g. because array is right at the end of a virtual memory page and the next page isn't mapped.
Demons fly out of your nose. Fortunately most computers lack the requisite hardware.
What you observed on Windows was that the compiler decided to place the variable i immediately after the array in memory, so array[10] = 0 ended up assigning to i. On Ubuntu and CentOS, the compiler didn't place i there. Almost all C implementations do group local variables in memory, on a memory stack, with one major exception: some local variables can be placed entirely in registers. Even if the variable is on the stack, the order of variables is determined by the compiler, and it may depend not only on the order in the source file but also on their types (to avoid wasting memory to alignment constraints that would leave holes), on their names, on some hash value used in a compiler's internal data structure, etc.
If you want to find out what your compiler decided to do, you can tell it to show you the assembler code. Oh, and learn to decipher assembler (it's easier than writing it). With GCC (and some other compilers, especially in the Unix world), pass the option -S to produce assembler code instead of a binary. For example, here's the assembler snippet for the loop from compiling with GCC on amd64 with the optimization option -O0 (no optimization), with comments added manually:
.L3:
movl -52(%rbp), %eax ; load i to register eax
cltq
movl $0, -48(%rbp,%rax,4) ; set array[i] to 0
movl $.LC0, %edi
call puts ; printf of a constant string was optimized to puts
addl $1, -52(%rbp) ; add 1 to i
.L2:
cmpl $10, -52(%rbp) ; compare i to 10
jle .L3
Here the variable i is 52 bytes below the top of the stack, while the array starts 48 bytes below the top of the stack. So this compiler happens to have placed i just before the array; you'd overwrite i if you happened to write to array[-1]. If you change array[i]=0 to array[9-i]=0, you'll get an infinite loop on this particular platform with these particular compiler options.
Now let's compile your program with gcc -O1.
movl $11, %ebx
.L3:
movl $.LC0, %edi
call puts
subl $1, %ebx
jne .L3
That's shorter! The compiler has not only declined to allocate a stack location for i — it's only ever stored in the register ebx — but it hasn't bothered to allocate any memory for array, or to generate code to set its elements, because it noticed that none of the elements are ever used.
To make this example more telling, let's ensure that the array assignments are performed by providing the compiler with something it isn't able to optimize away. An easy way to do that is to use the array from another file — because of separate compilation, the compiler doesn't know what happens in another file (unless it optimizes at link time, which gcc -O0 or gcc -O1 doesn't). Create a source file use_array.c containing
void use_array(int *array) {}
and change your source code to
#include <stdio.h>
void use_array(int *array);
int main()
{
int array[10],i;
for (i = 0; i <=10 ; i++)
{
array[i]=0; /*code should never terminate*/
printf("test \n");
}
printf("%zd \n", sizeof(array)/sizeof(int));
use_array(array);
return 0;
}
Compile with
gcc -c use_array.c
gcc -O1 -S -o with_use_array1.c with_use_array.c use_array.o
This time the assembler code looks like this:
movq %rsp, %rbx
leaq 44(%rsp), %rbp
.L3:
movl $0, (%rbx)
movl $.LC0, %edi
call puts
addq $4, %rbx
cmpq %rbp, %rbx
jne .L3
Now the array is on the stack, 44 bytes from the top. What about i? It doesn't appear anywhere! But the loop counter is kept in the register rbx. It's not exactly i, but the address of the array[i]. The compiler has decided that since the value of i was never used directly, there was no point in performing arithmetic to calculate where to store 0 during each run of the loop. Instead that address is the loop variable, and the arithmetic to determine the boundaries was performed partly at compile time (multiply 11 iterations by 4 bytes per array element to get 44) and partly at run time but once and for all before the loop starts (perform a subtraction to get the initial value).
Even on this very simple example, we've seen how changing compiler options (turn on optimization) or changing something minor (array[i] to array[9-i]) or even changing something apparently unrelated (adding the call to use_array) can make a significant difference to what the executable program generated by the compiler does. Compiler optimizations can do a lot of things that may appear unintuitive on programs that invoke undefined behavior. That's why undefined behavior is left completely undefined. When you deviate ever so slightly from the tracks, in real-world programs, it can be very hard to understand the relationship between what the code does and what it should have done, even for experienced programmers.
Unlike Java, C doesn't do array boundary check, i.e, there's no ArrayIndexOutOfBoundsException, the job of making sure the array index is valid is left to the programmer. Doing this on purpose leads to undefined behavior, anything could happen.
For an array:
int array[10]
indexes are only valid in the range 0 to 9. However, you are trying to:
for (i = 0; i <=10 ; i++)
access array[10] here, change the condition to i < 10
You have a bounds violation, and on the non-terminating platforms, I believe you are inadvertently setting i to zero at the end of the loop, so that it starts over again.
array[10] is invalid; it contains 10 elements, array[0] through array[9], and array[10] is the 11th. Your loop should be written to stop before 10, as follows:
for (i = 0; i < 10; i++)
Where array[10] lands is implementation-defined, and amusingly, on two of your platforms, it lands on i, which those platforms apparently lay out directly after array. i is set to zero and the loop continues forever. For your other platforms, i may be located before array, or array may have some padding after it.
You declare int array[10] means array has index 0 to 9 (total 10 integer elements it can hold). But the following loop,
for (i = 0; i <=10 ; i++)
will loop 0 to 10 means 11 time. Hence when i = 10 it will overflow the buffer and cause Undefined Behavior.
So try this:
for (i = 0; i < 10 ; i++)
or,
for (i = 0; i <= 9 ; i++)
It is undefined at array[10], and gives undefined behavior as described before. Think about it like this:
I have 10 items in my grocery cart. They are:
0: A box of cereal
1: Bread
2: Milk
3: Pie
4: Eggs
5: Cake
6: A 2 liter of soda
7: Salad
8: Burgers
9: Ice cream
cart[10] is undefined, and may give an out of bounds exception in some compilers. But, a lot apparently don't. The apparent 11th item is an item not actually in the cart. The 11th item is pointing to, what I'm going to call, a "poltergeist item." It never existed, but it was there.
Why some compilers give i an index of array[10] or array[11] or even array[-1] is because of your initialization/declaration statement. Some compilers interpret this as:
"Allocate 10 blocks of ints for array[10] and another int block. to make it easier, put them right next to each other."
Same as before, but move it a space or two away, so that array[10] doesn't point to i.
Do the same as before, but allocate i at array[-1] (because an index of an array can't, or shouldn't, be negative), or allocate it at a completely different spot because the OS can handle it, and it's safer.
Some compilers want things to go quicker, and some compilers prefer safety. It's all about the context. If I was developing an app for the ancient BREW OS (the OS of a basic phone), for example, it wouldn't care about safety. If I was developing for an iPhone 6, then it could run fast no matter what, so I would need an emphasis on safety. (Seriously, have you read Apple's App Store Guidelines, or read up on the development of Swift and Swift 2.0?)
Since you created an array of size 10, for loop condition should be as follows:
int array[10],i;
for (i = 0; i <10 ; i++)
{
Currently you are trying to access the unassigned location from the memory using array[10] and it is causing the undefined behavior. Undefined behavior means your program will behave undetermined fashion, so it can give different outputs in each execution.
Well, C compiler traditionally does not check for bounds. You can get a segmentation fault in case you refer to a location that does not "belong" to your process. However, the local variables are allocated on stack and depending on the way the memory is allocated, the area just beyond the array (array[10]) may belong to the process' memory segment. Thus, no segmentation fault trap is thrown and that is what you seem to experience. As others have pointed out, this is undefined behavior in C and your code may be considered erratic. Since you are learning C, you are better off getting into the habit of checking for bounds in your code.
Beyond the possibility that memory might be laid out so that an attempt to write to a[10] actually overwrites i, it would also be possible that an optimizing compiler might determine that the loop test cannot be reached with a value of i greater than ten without code having first accessed the non-existent array element a[10].
Since an attempt to access that element would be undefined behavior, the compiler would have no obligations with regard to what the program might do after that point. More specifically, since the compiler would have no obligation to generate code to check the loop index in any case where it might be greater than ten, it would have no obligation to generate code to check it at all; it could instead assume that the <=10 test will always yield true. Note that this would be true even if the code would read a[10] rather than writing it.
When you iterate past i==9 you assign zero to the 'array items' which are actually located past the array, so you're overwritnig some other data. Most probably you overwrite the i variable, which is located after a[]. That way you simply reset the i variable to zero and thus restart the loop.
You could discover that yourself if you printed i in the loop:
printf("test i=%d\n", i);
instead of just
printf("test \n");
Of course that result strongly depends on the memory allocation for your variables, which in turn depends on a compiler and its settings, so it is generally Undefined Behavior — that's why results on different machines or different operating systems or on different compilers may differ.
the error is in portion array[10] w/c is also address of i (int array[10],i;).
when array[10] is set to 0 then the i would be 0 w/c resets the entire loop and
causes the infinite loop.
there will be infinite loop if array[10] is between 0-10.the correct loop should be for (i = 0; i <10 ; i++) {...}
int array[10],i;
for (i = 0; i <=10 ; i++)
array[i]=0;
I will suggest something that I dint find above:
Try assigning array[i] = 20;
I guess this should terminate the code everywhere.. (given you keep i< =10 or ll)
If this runs you can firmly decide that the answers specified here already are correct [the answer related to memory stomping one for ex.]
There are two things wrong here. The int i is actually an array element, array[10], as seen on the stack. Because you have allowed the indexing to actually make array[10] = 0, the loop index, i, will never exceed 10. Make it for(i=0; i<10; i+=1).
i++ is, as K&R would call it, 'bad style'. It is incrementing i by the size of i, not 1. i++ is for pointer math and i+=1 is for algebra. While this depends on the compiler, it is not a good convention for portability.
sample 1
for(int i = 0 ; i <= 99 ; i++)
printf("Hello world");
sample 2
printf("Hello world"); // 1st print
printf("Hello world"); // 2nd print
.
.
.
printf("Hello world"); // 100th print
I know that sample one takes more time to execute than sample 2 and sample 2 takes more memory in text segment.
But,
I want to know that what's going on behind the scene.
Imagine sample one being written as this sequence of operations:
i = 0
if (i <= 99)
print
i++
jump
if (i <= 99)
print
i++
jump
if (i <= 99)
print
i++
jump
...
While the second sample is simply:
print
print
print
print
...
This is extremely simplified, but you should get the idea - the first sample executes many more instructions to go through the loop.
As a side note - this is one of the optimizations the compiler will frequently do - it will unroll the loop and compile it as if there was no loop. To do that, it has to come to the conclusion it is worth while - note that sample two will compile into much greater total number of instructions and will take much more space in memory (and therefore will take longer to load).
The code at sample 2 can be quicker if programmed properly.
As you have described, there are 100 calls to printf("... "); with the same string as parameter. If the compiler is an optimizing compiler, it can detect you are passing exactly the same parameter and don't pop the pointer after the call, so it won't need to push it again for the next call.
Also, the difference in speed between the loop is the time spent in jumping back to the beginning of the loop. With present architectures, that can be even an advantage, as the whole loop code is cached by the CPU (this cannot be done with a large set of similar calls) and no memory access is to be made to get the instructions loaded, compensating for the time spent in executing the loop instructions.
But... even, with a good optimizing compiler, it can detect you have put the same sentence 100 times and fold'em in a loop, with a hidden control variable (as in sample 1) so you don't se a difference in time on execution.
Optimizing compilers are used to detect these kind of constructions and to change the code to be more efficient.
A good reference for this kind of material is this: http://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools
I am trying to modify a value in an array using the C programming language and I seem to be hitting a blank wall with this seemingly easy operation. Please see code snippet below:
while(1) {
printf("Current prime candidate is %i\n",nextPrimeCandidate);
int innerSieve;//=2;
int currentPrimeCandidate=0;
for (innerSieve=2;innerSieve<SIEVELIMIT;innerSieve++) {
currentPrimeCandidate = nextPrimeCandidate * innerSieve;
//printf("Inner Sieve is b4 funny place %i,%i\n",innerSieve,currentPrimeCandidate);
//initArray[currentPrimeCandidate]=5;
//VERY UNIQUE LINE
myArray[currentPrimeCandidate] = 0;
//printf("Inner Sieve after funny place is %i,%i \n",innerSieve,currentPrimeCandidate);
}
nextPrimeCandidate=getNextPrimeCandidate(myArray,++nextPrimeCandidate);
if ((nextPrimeCandidate^2) > SIEVELIMIT ) break;
}
The problem is with the line highlighted with the VERY UNIQUE LINE comment. For some reason, when the innerSieve variable reaches 33 and gets to that line, it sets the contents of the innerSieve variable to the value of that line ( which currently is 0) and basically forces the loop into an infinite loop( the SIEVELIMIT variable is set at 50). It seems that there is some funny stuff going on in the registers when I checked using the Eclipse Debug facility but I am not too sure what I should be looking for.
If you need the whole code listing, this can be provided.( with a particular variable which is not yet initialised in the code being initialised at the precise point that the innerSieve variable hits 32)
Any help will be greatly appreciated.
Guessing that currentPrimeCandidate is greater than the maximum index of myArray, and you're overwriting innerSieve (which likely follows myArray on the stack).
#ruslik hit on it in the comment. The problem is this line:
if ((nextPrimeCandidate^2) > SIEVELIMIT ) break;
In C, the ^ operator is not the power operator, it is the bitwise xor operator. You're iterating far too many times than you intend, which is resulting in an array-index-out-of-bounds error, so you're overwriting random memory and getting strange results.
There is no power operator in C (though there is the pow function). Since you're just squaring a number, the simplest fix is to multiply the number by itself:
if ((nextPrimeCandidate * nextPrimeCandidate) > SIEVELIMIT ) break;