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;
}
Related
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.
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++;
}
}
I want to remove any spaces from the user input and give the result back on the screen. So far, the following is my working solution. I haven't noticed any errors yet. Since I'm pretty new to C and programming in general, my question is: Is there something I can do better? Anything to optimize or something? I appreciate any tips from you guys since you are probably a lot more experienced than I am. So, here's my code:
#include <stdio.h>
#include <string.h>
#define PUFFERGROESSE 100
#define ERROR 1
#define OK 0
int main(){
char stringPuffer[PUFFERGROESSE];
printf("Please enter some words:"); fflush(stdout);
if(fgets(stringPuffer, PUFFERGROESSE, stdin) == NULL){
printf("Unable to read.\n");
return ERROR;
} else {
char endString[PUFFERGROESSE];
for (int i = 0, j = 0; i < PUFFERGROESSE; i++, j++) {
if (stringPuffer[i] != ' ' ) {
endString[j] = stringPuffer[i];
} else {
j--;
}
}
printf("Without spaces your input looks like that: %s", endString);
}
}
In your code, the for loop condition is i < PUFFERGROESSE. Inside this loop, you access stringPuffer using the loop index.
Now, stringPuffer being an uninitialized automatic local variable and with a sufficiently small input, a strict check like i < PUFFERGROESSE will cause access to uninitialized memory of stringPuffer, creating undefined behavior.
You can make use of strlen() after taking the user input.
Another note, int main() is better as int main(void), at least.
NITPICK: why's the OK defined, if not used?
Several suggestions:
Initialize endString to all zeros; that way you won't have to worry about string termination issues later on:char endString[PUFFERGROESSE] = {0};
Instead of looping while i is less than PUFFERGROESSE, loop until you see the end of the string:for( int i = 0, j = 0; stringPuffer[i] != 0; i++ )
Also, only increment j when you write the non-space character, rather than incrementing it unconditionally and then having to decrement it when you see a space:if ( !isspace( stringPuffer[i] ) )
endString[j++] = stringPuffer[i];
So basically, that code reduces to:
char endString[PUFFERGROESSE] = {0};
for (int i = 0, j = 0; stringPuffer[i] != 0; i++) {
if ( !isspace( stringPuffer[i] ) ) {
endString[j++] = stringPuffer[i];
}
}
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)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm self-studying C and doing an exercise that, among other things, asks me to sort a list of user-entered strings by length of the first word in the string. The other functions in the exercise (including sorting the string by entire length) were easy to write. I've been working on this one for over three hours and can't get it to work. I'm sorting an array of pointers-to-char, and then printing them with a for loop in the main() function.
There's probably a much easier way to do this, but even if so, I cannot understand why this function doesn't work. I've made about thirty changes to it and the sort still comes out pretty random.
void srtlengthw(char * strings[], int n)
{
int top, seek, ct, ct_temp, i;
int ar_ct[n]
char * temp;
bool inWord;
for (top = 0, ct = 0, i = 0, inWord = false; top < n - 1; top++)
{
while (strings[top][i])
{
if (!isblank(strings[top][i]))
{
i++;
ct++;
inWord = true;
}
else if (!inWord)
i++;
else
break;
}
ar_ct[top] = ct;
for (seek = top + 1, ct = 0, i = 0, inWord = false; seek < n; seek++)
{
while(strings[seek][i])
{
if (!isblank(strings[seek][i]))
{
i++;
ct++;
inWord = true;
}
else if (!inWord)
i++;
else
break;
}
ar_ct[seek] = ct;
if (ar_ct[top] > ar_ct[seek])
{
ct_temp = ar_ct[top];
ar_ct[top] = ar_ct[seek];
ar_ct[seek] = ct_temp;
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
}}
Example of wrong output, as requested:
Input:
Mary
had
a
little
lamb
that
was
sacrificed
to
Satan
=========
Output:
had
a
little
lamb
that
was
sacrificed
to
Mary
Satan
And here's an example of a much simpler function that worked properly. It's meant to sort the pointers by length of the entire string rather than just the first word. I tried to model the word-length sort function on this one, but I'm apparently having trouble dealing with my counter variables and maybe my bool flag right.
void srtlength(char * strings[], int n)
{
int top, seek;
char * temp;
for (top = 0; top < n - 1; top++)
for (seek = top + 1; seek < n; seek++)
if (strlen(strings[top]) > strlen(strings[seek]))
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
For Craig, hopefully this helps?
Input:
They say it's lonely at the top, and whatever you do
You always gotta watch m*********s around you
Nobody's invincible
No plan is foolproof
We all must meet our moment of truth
The same sheisty cats that you hang with and do your thang with
Could set you up and wet you up, n***a, peep the language
It's universal
You play with fire, it may hurt you, or burn you
Lessons are blessins you should learn through
Output for me:
You always gotta watch m********s around you
Nobody's invincible
No plan is foolproof
We all must meet our moment of truth
The same sheisty cats that you hang with and do your thang with
Could set you up and wet you up, n***a, peep the language
It's universal
You play with fire, it may hurt you, or burn you
Lessons are blessins you should learn through
They say it's lonely at the top, and whatever you do
If you're looking for output similar to that of the example code that you posted, then I suggest using it as a template for a version with your expected behavior. The key that I'm looking to point out is that it sorts by the return value of the strlen function.
strlen is a function in C's <string.h> library (I think?) that returns the length of a C-style string. In C, as you're probably aware, the end of a string is identified by a null terminator, which is represented as a '\0'.
While the precise strlen may vary from one library to another, here is one standard implementation (made easier to read):
int strlen(char * str){
char * l;
for(l = str; *l != '\0'; l++);
return l - str;
}
People will likely argue that there are problems with this and it isn't perfect, but it does hopefully show how the length of a string is determined.
Now that we understand that the last example sorts by the total string length, and we know how string length is determined, we can probably make our own version of strlen that stops after the first word, instead of stopping at the null terminator:
int blank_strlen(char * str){
char * l;
for(l = str; *l != '\0' && !isblank(*l); l++);
return l - str;
}
Now, using the example code given:
void blank_srtlength(char * strings[], int n)
{
int top, seek;
char * temp;
for (top = 0; top < n - 1; top++)
for (seek = top + 1; seek < n; seek++)
if (blank_strlen(strings[top]) > blank_strlen(strings[seek]))
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
millinon's answer is a much better way to do it, as it is simpler. However, if you are looking for the reason why your code isn't working, it is due to your variables only being reset outside of each loop.
This code:
for (seek = top + 1, ct = 0, i = 0, inWord = false; seek < n; seek++)
{
while(strings[seek][i])
only sets ct, i and inWord once, before the loop is first started. When the program loops around, the values of ct, i and inWord will be kept from the last iteration.
Moving the assignments inside the loop like this:
for (seek = top + 1; seek < n; seek++)
{
ct = 0;
i = 0;
inWord = false;
while(strings[seek][i])
will fix your problem (you have to do it in both places).