How to convert nested loop construct into flow chart in C? - c

I'm drawing this code
if (V > 24)
{
do
{
PWM();
while (I = 0)
{
RA5 = 0;
LED();
I2C();
Delay_ms(1000);
RA5 = 1;
Delay_ms(1000);
if (I != 0)
{
break;
}
}
LED();
I2C();
} while (v < 28.7)
}
to this
I really don't know how to deal with this nested loop, is there any better idea for it?

Unrelated, but
if(I != 0){
break;
}
Is implied by the for loop, you don't need it. Also be careful:
while(I=0)
will set I to 0 and your loop will never exit! You may have found this and decided to add the break later to compensate. What you want is:
while(I==0)
Note that what you did with the do while is correct, and a while loop is the same except the check happens before entering the loop rather then when exiting the loop. Remove the break and have your arrow simply go back to before the check for I == 0.

Related

top level `continue` in nested loop C instead of current level loop

How do I make continue goes to the top level of loop? I mean like this:
for(;;){ // top level loop
statement1;
for(;;){ // second level loop
statement2;
if (condition1){
continue; // I expect it continue to the start of top level so it will execute statement1.
}
}
statement3;
}
This is my real case why I got problem above, basically my program is sending data with UDP socket which the data should be sent fast. I know UDP is unrealiable but it's okay the data is tolerated with loss too.
for (;;) { // Streaming data...
camera_fb_t* fb = esp_camera_fb_get();
size_t quotient = fb ->len / UDP_BUF_SIZE;
size_t remainder = fb ->len % UDP_BUF_SIZE;
unsigned int i = 0;
for (; i < quotient; i++) { // sending packet by packet.
if (uwc_udp_send_raw((const void*)(fb ->buf + (i * UDP_BUF_SIZE)),
UDP_BUF_SIZE) < 0) {
ESP_LOGE(uwc_tag_event, "Error in itteration: %i", i);
uwc_udp_send_raw("ERR",3); // Tell receiver there was corrupt during send data.
esp_camera_fb_return(fb);
continue; // I expect it continue to the top level
}
}
if (remainder) { // last packet to be sent if remainder exist
uwc_udp_send_raw((const void*)(fb ->buf + (i * UDP_BUF_SIZE)),
remainder);
ESP_LOGE(uwc_tag_event, "Error in last itteration!");
}
esp_camera_fb_return(fb);
}
This is a rare case where you may use a goto. * Ducks for cover expecting flame-war and down votes *
People will get excited and declare your code automatically unreadable by a single use of goto and generally wring their hands.
But in these very rare cases the cleanest and most readable code has a goto. There are exceptions to almost every rule!
Remember, there is almost always a better way than using goto but the real issue with it is that liberal use quickly creates 'spaghetti' code.
But a single use can be justified.
#include <stdio.h>
int foo(){
for(int i=0;i<10;++i){
for(int j=0;j<10;++j){
if(j==i*i){
goto OUTER_LOOP;
}
}
printf("%d\n",i);
OUTER_LOOP: continue;
}
}
int main(void) {
foo();
return 0;
}
People will claim you should set a boolean and break and insist that is 'more readable'. It's no more readable at all.
There are few dogmatic laws in programming but "goto is always an necessarily bad" is one of them. It's almost true. But not quite entirely true.
Java has a labelled break statement almost specifically to provide a way of avoiding this use-case for goto and doesn't have goto itself because it has a fix.
I think it's arguable that there is a tiny gap in the language. But in practice this situation is actually quite rare.
You don't need a flag or continue or goto:
for (;;) {
camera_fb_t *uwcCamFb = esp_camera_fb_get();
unsigned char *from = uwcCamFb->buf;
size_t toSend = uwcCamFb->len;
for( int i = 0; toSend > 0; i++ ) {
size_t sendSize = toSend > UDP_BUF_SIZE ? UDP_BUF_SIZE : toSend;
if( uwc_udp_send_raw( from, sendSize ) < 0) {
ESP_LOGE( uwc_tag_event, "Error in itteration: %i", i );
uwc_udp_send_raw( "ERR", 3 );
break;
}
toSend -= sendSize;
from += sendSize;
}
// Update...
// Removed conditional as it reflected flawed OP logic...
// if( toSend == 0 )
esp_camera_fb_return( uwcCamFb );
}
If you need/want to distinguish the LAST packet, add if( toSend < UDP_BUF_SIZE ) to log that particular error message instead...
It seems your OP used both fb and uwcCamFb... I can only guess this corrects that apparently mistake...
(Thank you to #Persixty for a bug report that has been fixed.)
I think goto can solve this problem, I would not use it in normal situation but this is acceptable I think, define a label in the top level for and use goto label in the inner one :]
It's up to you if you want a boolean and check it in every inner loop or use a goto though.
Edit: Honestly 2 for loop are not much, maybe a simple if condition is enough
You need flags:
for(int i = 0; i < 15; i ++)
{
int execST3 = 1;
printf("ST1 i = %d\n", i);
for(int j = 0; j < 15; j ++)
{
printf("ST2 j = %d\n", j);
if(j == 3) {execST3 = 0; break;}
}
if(execST3)printf("ST3\n");
}
The code can be made to work cleanly by replacing the inner infinite loop with a goto style infinite loop. From the compiler point of view that eliminates the second for loop, so that the continue, continues at the first infinite loop.
for (;;)
{
statement1;
INNER_LOOP:;
{
statement2;
if (condition1)
{
continue; // at the top of the first loop.
}
goto INNER_LOOP;
}
statement3;
}

How to convert a C ternary statement into an if/else if declared within an if condition?

So after looking on the massive interweb, I was unable to find an answer to this.
Say I have this piece of code:
if(P4IN & GPIO_PIN1?0:1){
if (state==1){
state = 0;
//Wait for this state to pass -- ends up saving the current state on button press.
while (counter < 10000){
counter++;
}
}
else{
state = 1;
while (counter < 10000){
counter++;
}
}
}
How would I rewrite this so that if(P4IN & GPIO_PIN1?0:1) is not written like this. I do not mind creating extra if/else conditions or extending this block of code (intended for the MSP432)
Thanks for your time.
You can simplify the whole thing to this:
if (!(P4IN & GPIO_PIN1)) {
state = !state;
while (counter < 10000) {
counter++;
}
}

How to avoid 'while(true)' with 'break' and rather use a 'for' loop?

I have an application with a config file from which various settings are read. One of the settings is the cycles that the application is running.
If this variable nLoops is -1 then it's supposed to run an infinite number of times. Otherwise it shall run x times.
At the moment this is how I implemented it. However I was wondering if there's a more straight forward way without the while(true) expression (I get a warning here):
//get nLoops from config file
int i = 0;
while (true)
{
if (nLoops > -1 && i >= nLoops)
break;
i++;
// do stuff
}
Just put the if condition (inverted, since you're testing to stay in instead of break out) in the while condition:
while (nLoops == -1 || i < nLoops)
Or as a for:
for (i=0; (nLoops == -1) || (i < nLoops); i++)
You can replace while(true) with for(;;) to avoid warnings. The for loop with a missing controlling expression is explicitly defined in the standard, e.g., ISO/IEC 9899:1999 6.8.5.3/2.
This requires one more (boolean) variable, but avoid using break statement in your loop.
// Here reads from configuration file
bool isInfiniteLoop = false;
i = 0;
if(nLoops == -1)
{
isInfiniteLoop = true;
nLoops = 1;
}
while(i < nLoops)
{
// here goes your code
if(!isInfiniteLoop)
{
// If NOT infinite loop: increment counter, otherwise while condition will always be 0 < 1
i++;
}
}

Arrays in Arduino

I am trying to create an array and be able to compare the second to last and last item in an array. It needs to be constantly adding and comparing to work correctly. This is just a function I am trying to get running to help control a stepper motor function. I have a loop that is going to fast for me to be able to compare directly. I do know that some of it is wrong but as I haven't coded in C very much I can't figure out how to use an array correctly. Thank you in advance.
int P[10],V[10],i,x,y;
Serial.print("checkvalue = ");
Serial.print(checkvalue);Serial.print("\n");
Serial.print("P = "); Serial.print(P[i]); Serial.print("\n"); //attempting to print array
Serial.print("V = "); Serial.print(V[i]); Serial.print("\n"); //to see if it is collecting
//data correctly
//these variables are declared above in my code, just didn't copy in
Dgreadpb = digitalRead(13);
PBcheck = Dgreadpb;
//Serial.print("Button in = ");Serial.print(Dgreadpb); Serial.print("\n");
Dgreadvls = digitalRead(12);
VLScheck = Dgreadvls;
//Serial.print("Photo in = ");Serial.print(Dgreadvls); Serial.print("\n");
for (i = 0; i < 10; i++){
x = Dgreadpb;
y = Dgreadvls;
P[i] = x;
V[i] = y;
if (P[i-1] == P[i] && V[i-1] == V[i]){ //trying to compare second to
checkvalue == 0; //last term to the last term
return;
}
else if(P[i-1] != P[i] || V[i-1] != V[i]){
checkvalue == 1;
return;
}
}
delay (1000);
By "trying to compare second to last term to the last term", do you mean "Trying to compare second to last term with their previous"? If that's the case your indices are wrong, it should be for(i = 1; i<10; i++).
Also both conditions are opposite (Either both are equal or AT LEAST one of them is different), there is no need for else if. Even more, cause both conditions are opposite it will never complete the loop. I think that's not the intention, if you're trying to say that only one of them are different you should do:
if (P[i-1] == P[i] && V[i-1] == V[i]){ //If both are equal
checkvalue == 0;
return;
}
else if(P[i-1] == P[i] || V[i-1] == V[i]){ //If only one is equal
checkvalue == 1;
return;
}
Ok, then I'd make a different thing.
Looking at your comment, it looks like you want to do something like this: read the value of two pins, compare them to the last value you read and, if they are differernt, start the motor, otherwise stop it.
Now, a lot of info are missing (e.g. how do you check the motor? how often do you want to check the sensor? what sensor?) but IMHO you should do something like this.
In this code I suppose that
you want to check the sensor every 100 milliseconds
if the values differ, you want to turn on the motor for the next 100 ms
the motor is a DC motor turned on by setting the corresponding pin (e.g. 10)
the sensors have a binary output on pins 12 and 13, since you wrote that in the code
BTW I used the millis() function because I hate the delay, since it blocks the uC. Using my function you'll be able to perform other operations while it is idle.
const byte motorPin = 10;
const byte sensorPPin = 12;
const byte sensorVPin = 13;
#define LOOP_TIME_MS 100
unsigned long lastLoopTime;
boolean lastPval, lastVval;
void setup()
{
pinMode(motorPin, OUTPUT);
pinMode(sensorPPin, INPUT);
pinMode(sensorVPin, INPUT);
lastPval = digitalRead(sensorPPin);
lastVval = digitalRead(sensorVPin);
lastLoopTime = millis();
}
void loop()
{
if ((millis() - lastLoopTime >= LOOP_TIME_MS)
{
boolean Pval = digitalRead(sensorPPin);
boolean Vval = digitalRead(sensorVPin);
if ((Pval != lastPval) || (Vval != lastVval))
{
digitalWrite(motorPin, HIGH);
}
else
{
digitalWrite(motorPin, LOW);
}
lastLoopTime += LOOP_TIME_MS;
}
/* Here you can do something else */
}
EDIT: If, on the other side, you want to use arrays (because you want to test the last N values instead of just the previous one) please provide further info on what are the changing conditions (or better provide examples)

Stuck in a nested do { for { if loop

So with this bit of code the program hangs up and won't exit the loop, the printfs were just put in for debugging and they aren't integral to the program. I am pretty new to programming so I am not sure what I am missing the logic seems like it should work. Thank you very much for taking the time to look over this and your help.
do
{
intialcollide = 0;
for(i=0; i<11; i++)
{
if(i != currentObj)
{
if(object[currentObj].new_loctX == object[i].new_loctX && object[currentObj].new_loctY == object[i].new_loctY)
{
intialcollide = 1;
}
else
{
intialcollide = 0;
}
}
printf("%d\n", intialcollide);
}
}while(intialcollide != 1 || i != 10);
printf("Collide? %d", intialcollide);
When I run it I get infinite 1's and 0's. Thanks again for the help
At the end of your for loop, i will always equal 11. Maybe you thought it would equal 10? Anyways, there is no point comparing i to anything in the while condition because you know it is always the same value.
Add a "break;" whenever you set intialcollide to 1. Your for loop is resetting the value to 0 before it hits the while loop check.

Resources