Why is this inconsequential variable initialized within a for loop? - c

In the program I have pasted below, I was just wondering why the pointer "p" was initialized within the for loop? I am used to reading the conditions of a for loop as: starting from this value of a variable; until it reaches this value; increment it by this much. So it seems strange to have another variable that does not determine the ending condition and is not being incremented during each iteration in there at all.
I would have just put p=&a[0]; above the for loop and left the rest. Is this just a stylistic thing or are there differences in the way things are processed depending on where you initialize p? Is one way preferred over the other?
#include <stdio.h>
#define PRD(a) printf("%d", (a) )
int a[]={0, 1, 2, 3, 4};
int main()
{
int i;
int* p;
for (p=&a[0], i=0; i<=4; i++) PRD(p[i]);
return 0;
}

This appears to be just a style thing. I would probably have also put the initialisation of p outside the for statement, since cramming everything in there makes the code harder to read. (Because the pattern of that for loop is different from what you might usually expect, an experienced programmer will have to stop, back up, and think about what's in there before it will make sense. I initially thought there were four clauses in the for control statements until I noticed that the first separator was a comma.)
Writing the code like this (instead of initialising p outside the loop) will have no effect on performance.

Related

Understanding the reason behind a output

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

How to include last element in loops in C?

This is a general issue I've run into, and I've yet to find a solution to it that doesn't feel very "hack-y". Suppose I have some array of elements xs = {a_1, a_2, ..., a_n}, where I know some x is in the array. I wish to loop through the array, and do something with each element, up to and including the element x. Here's a version that does almost that, except it leaves out the very last element. Note that in this example the array happens to be a sorted list of integers, but in the general case this might not necessarily be true.
int xs[] = {1,2,3,4,5};
for (int i = 0; xs[i] != 4; i++) {
foo(xs[i]);
}
The only solutions I've seen so far are:
Just add a final foo(xs[i]); statement after the for-loop. This is first of all ugly and repetitious, especially in the case where foo is not just a function call but a list of statements. Second, it requires i to be defined outside the scope of the for-loop.
Manually break the loop, with an if-statement inside an infinite loop. This again seems ugly to me, since we're not really using the for and while constructs to their full extent. The problem is almost archetypal of what you'd use a for-loop for, the only difference is that we just want it to go through the loop one more time.
Does anyone know of a good solution to this problem?
In C, the for loop is a "check before body" operation, you want the "check after body" variant, a do while loop, something like:
int xs[] = {1,2,3,4,5};
{
int i = 0;
do {
foo(xs[i]);
} while (xs[i++] != 4);
}
You'll notice I've enclosed the entire chunk in its own scope (the outermost {} braces). This is just to limit the existence of i to make it conform more with the for loop behaviour.
In terms of a complete program showing this, the following code:
#include <stdio.h>
void foo(int x) {
printf("%d\n", x);
}
int main(void) {
int xs[] = {1,2,3,4,5};
{
int i = 0;
do {
foo(xs[i]);
} while (xs[i++] != 4);
}
return 0;
}
outputs:
1
2
3
4
As an aside, like you, I'm also not that keen of the two other solutions you've seen.
For the first solution, that won't actually work in this case since the lifetime of i is limited to the for loop itself (the int in the for statement initialisation section makes this so).
That means i will not have the value you expect after the loop. Either there will be no i (a compile-time error) or there will be an i which was hidden within the for loop and therefore unlikely to have the value you expect, leading to insidious bugs.
For the second, I will sometimes break loops within the body but generally only at the start of the body so that the control logic is still visible in a single area. I tend to do that if the for condition would be otherwise very lengthy but there are other ways to do this.
Try processing the loop as long as the previous element (if available) is not 4:
int xs[] = {1,2,3,4,5};
for (int i = 0; i == 0 || xs[i - 1] != 4; i++) {
foo(xs[i]);
}
This may not be a direct answer to the original question, but I would strongly suggest against making a habit of parsing arrays like that (it's like a ticking bomb waiting to explode at a random point in time).
I know you said you already know x is a member of xs, but when it is not (and this can accidentally happen for a variety of reasons) then your loop will crash your program if you are lucky, or it will corrupt irrelevant data if you are not lucky.
In my opinion, it is neither ugly nor "hacky" to be defensive with an extra check.
If the hurdle is the seemingly unknown length of xs, it is not. Static arrays have a known length, either by declaration or by initialization (like your example). In the latter case, the length can be calc'ed on demand within the scope of the declared array, by sizeof(arr) / sizeof(*arr) - you can even make it a reusable macro.
#define ARRLEN(a) (sizeof(a)/sizeof(*(a)))
...
int xs[] = {1,2,3,4,5};
/* way later... */
size_t xslen = ARRLEN(xs);
for (size_t i=0; i < xslen; i++) {
if (xs[i] == 4) {
foo( xs[i] );
break;
};
}
This will not overrun xs, even when 4 is not present in the array.
EDIT:
"within the scope of the declared array" means that the macro (or its direct code) will not work on an array passed as a function parameter.
// This does NOT work, because sizeof(arr) returns the size of an int-pointer
size_t foo( int arr[] ) {
return( sizeof(arr)/sizeof(*arr) );
}
If you need the length of an array inside a function, you can pass it too as a parameter along with the array (which actually is just a pointer to the 1st element).
Or if performance is not an issue, you may use the sentinel approach, explained below.
[end of EDIT]
An alternative could be to manually mark the end of your array with a sentinel value (a value you intentionally consider invalid). For example, for integers it could be INT_MAX:
#include <limits.h>
...
int xs[] = {1,2,3,4,5, INT_MAX};
for (size_t i=0; xs[i] != INT_MAX; i++) {
if (xs[i] == 4) {
foo( xs[i] );
break;
};
}
Sentinels are quite common for parsing unknown-length dynamically-allocated arrays of pointers, with the sentinel being NULL.
Anyway, my main point is that preventing accidental buffer overruns probably has a higher priority compared to code prettiness :)

C for loop, supposed to be able to omit initialization inside loop itself, doesn't work as intended

so I'm slowly trying to learn C from scratch.
I'm at a point in the book I'm using where an exercise is proposed: use nested loops to find Pythagorean triplets. Now I'll show the code.
#include <stdio.h>
int main(void){
int lato1=1;
int lato2=1;
int ipotenusa=1;
for(;lato1 <= 500; lato1++){
for(;lato2 <= 500; lato2++){
for(;ipotenusa <= 500; ipotenusa++){
if (((lato1 * lato1)+(lato2 * lato2))==(ipotenusa*ipotenusa)){
printf("Tripletta %10d %10d %10d\n",lato1,lato2,ipotenusa);
}
}
}
}
return 0;
}
now, apart from terrible formatting and style, apart from the shi*t optimization,
the code as shown, doesnt work.
It only execute the inner most loop, and then the program ends.
If, however, I initialize each variable/counter inside each loop then it works.
Why?
I read that for loop initialization is valid even whitout no arguments (;;) but in this case I just wanted to initialize those variables before the loop, let's say because I wanted to access those value after the loop is done, it just doesn't seem to work like it's supposed to.
English is not my primary language so apologies in advance for any mystake.
Can somebody explain what is the problem?
Edit 1: So, I don't know if it was my bad English or something else.
I said, if I declare and initialize the variables before the loop, like in the code I've shown you, it only goes through the inner most loop (ipotenusa) and it does so with the following output values: 1 1 1 then 1 1 2 then 1 1 3 and so on, where the only increasing number is the last one (ipotenusa); AFTER we reach 1 1 500 the programs abruptily ends.
I then said that if I initialize the variables as normal, meaning inside the for loop instruction, then it works as intended.
Even if declared earlier there is NO reason it should't work. The variable's value it's supposed to increase. Up until now the only useful answer was to initialize a variable outside the loop but assign a value to it in the loop statement, but this is not at the end the answer I need, because I should be able to skip the initialization inside the loop statement altogether.
EDIT 2: I was wrong and You guys were right, language barrier (most likely foolishness, rather) was certainly the cause of the misunderstanding lol. Sorry and Thanks for the help!
You accidentally answered your own question:
...in this case I just wanted to initialize those variables before the loop, let's say because I wanted to access those value after the loop is done...
Think about the value of ipotenusa...or have your program print out the value of each variable at the start of each loop for debugging purposes. It'll look something like the following log.
lato1: 1
lato2: 1
ipotenusa: 1
ipotenusa: 2
ipotenusa: 3
ipotenusa: 4
ipotenusa: 5
lato2: 2
lato2: 3
lato2: 4
lato2: 5
lato1: 2
lato1: 3
lato1: 4
lato1: 5
The inner loops never "reset," because you're saving the value. You're not wrong on either count, but you've set up two requirements that conflict with each other, and the C runtime can only give you one.
Basically, lato2 and ipotenusa need to be initialized (but not necessarily declared) in their for statements, so that they're set up to run again.
int lato1=1;
int lato2;
int ipotenusa;
for(;lato1 <= 5; lato1++){
for(lato2 = 1;lato2 <= 5; lato2++){
for(ipotenusa = 1;ipotenusa <= 5; ipotenusa++){
if (((lato1 * lato1)+(lato2 * lato2))==(ipotenusa*ipotenusa)){
printf("Tripletta %10d %10d %10d\n",lato1,lato2,ipotenusa);
}
}
}
}
It's worth pointing out that, even though the specification might (or might not; I don't remember and am too fuzzy to look it up, right now) say that the loop variables only exist during the loop, I've never seen an implementation actually do that, so you'll see a lot of code out there that defines the variable inside of for and uses it after. It's probably not great and a static checker like lint might complain, but it's common enough that it'll pass most code reviewers, to give you a sense of whether it can be done.
Your code does exactly what you told it to do.
If you initialise lato2 with a value of 1, what makes you think that the initialisation will be repeated at the start of the inner for loop? Of course it isn't. You told the compiler that you didn't want it to be initialised again. After that loop executed the first time, lato2 has a value of 501, and it will keep that value forever.
Even if it hadn't produced a bug, putting the initialisation and the for loop so far apart is very, very bad style (wouldn't pass a code review in a professional setting and therefore would have to be changed).
for (int lato2 = 1; lato2 <= 500; ++lato2) is clear, obvious, and works.
One approach would be - declaring variables outside of the loop and initialize them inside. This way, you can access the variables after the loops.
#include <stdio.h>
int main(void){
int lato1, lato2, ipotenusa;
for(lato1=1; lato1 <= 500; lato1++){
for(lato2=1; lato2 <= 500; lato2++){
for(ipotenusa=1; ipotenusa <= 500; ipotenusa++){
if (((lato1 * lato1)+(lato2 * lato2))==(ipotenusa*ipotenusa)){
printf("Tripletta %10d %10d %10d\n",lato1,lato2,ipotenusa);
}
}
}
}
return 0;
}
You are using variables that are initialized outside of the for loops. Usually what happens is when we use inner loops(nested loops) we intended to initialize it with base value everytime but in your case it is never going to do that. Since you have initialized variable out side of the for loops so it will persist its value through out its life time of course which is main function in this case.

for loop containing all equals statements C

I'm trying to understand a coding example I found in C, and one of the for loops is structured like this:
for(int x=0; int y=0; int z!=0){some code}
I am used to seeing something more like this:
for(int x=0; x < someLimit; x++){some code}
What does the mystery for loop do exactly?
You copied the statement wrong. In the program you cited in your comment there's only one for statement which approximates what you posted above:
for(time=0,count=0;remain!=0;)
In this case the "initialization" portion of the for statement is
time=0,count=0
Note that the character between the initialization of time and count is a comma, not a semicolon. This means
that both time and count are set to zero. The "test" portion of the for statement is
remain != 0
meaning that the loop will continue as long as remain is not equal to zero.
In this for statement the "increment" portion is empty - so nothing is incremented/decremented/whatever at the end of each pass through the loop.
Best of luck.
In for loop you can omit initialization part(provided you initialized your variable before) and increment/decrement part. you can have also multiple initialization like in your example x=0;y=0 and multiple increment/decrement. in your first example for loop have multiple initialization for x and y and no increment/decrement part. and z part is the condition. Please check why you are declaring z there. I am not sure about that. It would be better if you will upload full code of that example.

C loops-OK to change counter or condition within loop?

Several books show me how to correctly write for, while, and do loops.
Lots of online articles compare them to each other.
But I haven't found any place that tells me what not to do. For example, would it screw things up if I change the value of the counter or condition variable within the loop?
I would like an answer that is not machine dependent.
Yes you can change the counter within a loop and it can sometimes be very useful. For example in parsing command line arguments where there is an option flag followed by a value. An example of this is shown below:
Enter the following command:
program -f filename -o option -p another_option
Code:
#include <string.h>
int main(int argc, char** argv)
{
char *filename, *option, *another_option;
if(argc > 1){
for(int i=1; i<argc; i++){
if(strcmp(argv[i],"-f")==0){
filename = argv[++i];
} else if(strcmp(argv[i],"-o")==0){
option = argv[++i];
} else if(strcmp(argv[i],"-p")==0){
another_option = argv[++i];
} else {
printf("Option \"%s\" not recognized, skipping\n",argv[i]);
continue;
}
}
} /* end if argc > 1 */
return 0;
}
The example program automatically increments the counter to access the correct command line string. There are of course ways to incorporate counters etc., but they would only make the code more cumbersome in this case.
As others have pointed out, this is where many people write bugs and one must be careful when incrementing counters within loops, particularly when the loop is conditional upon the counter value.
It is not invalid to change a loop counter inside a loop in C.
However, it is probably confusing to future readers and that's a good reason not to do it.
It depends on what you mean by "screw things up".
If you know what you are doing, you can change counter. The language has no restrictions on this.
Changing the counter variable in the loop is allowed, but be careful to know what you are doing to not create infinite loops by decreasing the variable when you shouldn't be.
Some algorithms actually benefit from this, but of course if you do this it makes your code less readable so make sure you comment what you are doing also.
Yes, you can change the counter and condition variables. They will just be evaluated with the next iteration of the loop.
Definiteley you can.But be careful not to make the loop disorder. Alter a conter in the loop happens a lot in do...while and while.
do{
counter++;
some expressions;
}
while(counter < SOMEVALUE);
Yes, in C/C++/C# You can change the counter etc. in the loop.
Like many other techniques, as long as you know what do you do, it's fine.
For example, this code:
int i;
for (i=0;i<5;i++)
printf("%d\n",i--);
is an infinity loop, but this version of bubble sort:
int *arr,n;
//allocate memory, assign values, and store the length of the array in n
int i;
for (i=0;i<n-1;i++)
if (arr[i]>arr[i+1]) {
int temp=arr[i];
arr[i]=arr[i+1];
arr[i+1]=temp;
if (i) i-=2;
}
is fine. (It's not exactly bubble sort. Instead of using nested loops, I go back in the array after swapping members in it)
Be careful changing counter variable inside a loop, not all loops are the same, "while" loop behaves differently. see this example?
No, it is NOT an infinite loop (on some compilers). run it, and see...
i=5;
while (i--)
{
i=100;
printf("%d \n",i)
}
We can change the counter value inside the loop but the final counter value wont be reflected as the for loop wont override the counter value.
here is the example in QTP VB script.
iLast = 4
For i= 1 to iLast
iLast=2
Next
Here the for loop should execute only for 2 times as iLast value is updated to 2 inside the loop but it is executing for 4 times.

Resources