Implementing loops on the basis of condition in C - c

I have a set of statements that need to be executed in two different loops; the loops identified on the result of a check condition. There are multiple such sets of this type.
Set A : statement 1
statement 2
statement 3
Set B : statement 4
statement 5
statement 6
and so on..
Now they need to be executed as follows:
if(condition 1)
loop over some Loop A
execute Set A
else if(condition 2)
loop over some loop B
execute Set A
These loops can be completely different from each other.
Now, for the sake of code clarity, I don't wish to write the code as mentioned above. Another reason being I'll have to make multiple sets in order to group them together.
Is there any mechanism by which I could achieve the following:
CHECK_CONDITION_AND_LOOP_HERE
execute Set A
I've tried using macros to achieve this, using braced-group within expression but could not . I also tried using ternary operators as well as fall through a switch case to achieve this, but could not get the same result.
Is there any way in C using which I could achieve the desired behavior?
Sample code for the problem:
if(condition A)
for(i=0; i<10; i++, k*=2) {
execute Set A; //Operations performed here use variable k
}
else if(condition B)
for(j=5; j<75; j+=5, k*=arr[j]) {
execute Set A; //Operations performed here use variable k
}

The answer to Version 1 of the question:
Given that the only difference is the range of values over which the statements are executed, you can use a couple of variables to store the range end-points, e.g.
int first = 0;
int last = -1;
if (condition1) {
first = 1;
last = 10;
} else if (condition2) {
first = 3;
last = 7;
}
for ( int i = first; i <= last; i++ )
execute set A
Note that initializing last to be less than first prevents the body of the loop from running if neither condition is met.
The answer to Version 2 of the question:
Here's the code from the question. I've made some changes for clarity, and to make the question more concrete.
if (cond1)
for (initA;condA;updateA)
execute SetX
else if (cond2)
for (initB;condB;updateB)
execute SetX
Here's the refactored code
int is1 = cond1;
int is2 = is1 ? 0 : cond2;
if (is1)
initA;
if (is2)
initB;
while ( (is1 && condA) || (is2 && condB) )
{
execute SetX
if ( is1 )
updateA;
if ( is2 )
updateB;
}

A function, maybe?
void func_A() {
printf("Here0\n");
printf("Here1\n");
}
...
if(a < b) {
for(i = 1; i <= 10; i++) {
func_A()
}
}
else if(a == b) {
for(i = 3; i <= 7; i++) {
func_A()
}
}
Or if you want to only make one call/block:
if(a < b) {
min = 1; max = 10;
}
else if(a == b) {
min = 3; max = 7;
}
for(i = 3; i <= 7; i++) {
printf("Here0\n");
printf("Here1\n");
}

Related

Error C2360 Initialization of "arr2" is skipped by "case" tag

I am new to programming.
This is a C language program.
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdbool.h>
#define ture 1
#define false 0
void add(int m, int* arr,int n)
{
if (n == 32) return;
arr[n] += m;
if ( arr[n] > 1)
{
arr[n] = 0;
add(m, arr, ++n);
}
return;
}
int main(void)
{
int T,n,r,m,i,j,k;
bool check = ture;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &r);
switch (r)
{
case 10:
printf("%d", n);
break;
case 2:
int arr2[32] = { 0 };
if (n > 0)
{
for (i = 0; i < 32 ; i++)
{
arr2[i] = n % 2;
n = n / 2;
}
for (j = 31; j >= 0; j--)
{
if (arr2[j] == 0 && check == ture) continue;
else
{
check = false;
printf("%d", arr2[j]);
}
}
}
else if (n == 0)printf("%d", 0);
else if (n < 0)
{
n = -n;
for (i = 0; i < 32; i++)
{
arr2[i] = n % 2;
n = n / 2;
}
for (k = 0; k < 32; k++)
{
arr2[k] = !arr2[k];
}
add(1, arr2, 0);
for (j = 31; j >= 0; j--)
{
if (arr2[j] == 0 && check == ture) continue;
else
{
check = false;
printf("%d", arr2[j]);
}
}
break;
}
case 8:
int arr8[11] = { 0 };
if (n > 0)
{
for (i = 0; i < 11; i++)
{
arr8[i] = n % 8;
n = n / 8;
}
for (j = 10; j >= 0; j--)
{
if (arr8[j] == 0 && check == ture) continue;
else
{
check = false;
printf("%d", arr8[j]);
}
}
}
}
}
return 0;
}
When I run the program in VS2022.There is a bug.
Error C2360 Initialization of "arr2" is skipped by "case" tag Project5 C:\code\C\C_Single\Project5\Project5\test.cpp 74
I don't understand why this is happening.
In my opinion,when I select the contents of case8, I don't need the contents of case2, certainly,including the declaration of arr2.But obviously the compiler doesn't think that way.
So I turn to google for help.
However,google tells me something like this.
Your search - Error C2360 Initialization of "arr2" is skipped by "case" tag - did not match any documents.
Suggestions:
Make sure that all words are spelled correctly.
Try different keywords.
Try more general keywords.
Try fewer keywords.
So I want to get help in stackoverflow.Can anyone help me?
This is one reason that goto statements are frowned upon in modern code.
A case label is not much more that a regular label, and the switch will do something like:
if(value==2) goto label2;
if(value==3) goto label3;
etc.
But when you declare an array like:
int arr[10];
or actually any variable that goes on the stack, the compiler needs to increase the stack pointer to make space for that. in this case:
sp += 10 * sizeof(int)
(Of course this depends on your system/compiler etc)
So what happens if you put this piece of code, in between to (case) labels...
label2:
//int arr[10];
sp += 10*sizeof(int);
label3:
...
// end of scope for arr
sp -= 10*sizeof(int);
// or not?
Yeah it happens only half the time. So now you end up at the end of you switch statement, and your compiler doesn't know weather to decrease the stack pointer or not.
The compiler warns you that the initialization of the array arr2 can be skipped if the control will be passed to the label case 8:. In this case the array will have indeterminate values.
To avoid the compiler message just enclose statements after labels in braces creating a compound statement like for example
case 2:
{
int arr2[32] = { 0 };
//...
}
You have several problems here, within your switch(). (I'm just going to focus on that.)
Firstly, declaring variables within case clauses is problematic: providing them with initialisers, even more so. If you enclose the entire case clause within curly braces, that's a lot better. You also constrain the scope of your case-dependent variables to within that specific case.
Secondly, you have a significant logic error in your switch() statement. Your case 2: clause only hits a break in the n < 0 instance: in all others, it will fall through to case 8:. This is very clearly incorrect.
Thirdly, your case 8: clause has no break statement. As it's the last in the switch(), that's benign - you'll "fall out the bottom", but it's bad practice.
Finally, there is no default: clause. In just about every situation you use a switch() you want to catch the default: case, as it's either going to need a default handling, or it indicates an error condition.
In summary: brace your case clause code, so you can do as you with with, and scope, the variables you declare, and be rigorous about break and default: use. You'll thank me in the future!

For loop instead of long if condition in order to reduce computing time

I have some code that looks like shown below. I have simplified it to get my point across. It contains an array. In the first part each value of the array minus a certain value shall be compared to a margin value.
If all of the conditions are met the µC should stop run a simple function.
Else the µC should run a calculation with the values of the array. This calculation has a few multiplications that are run for every value.
uint32_t value[8];
uint16_t othervalue;
if ((value[0] < othervalue && value[1] < othervalue && value[2] < othervalue && value[3] < othervalue && value[4] < othervalue && value[5] < othervalue && value[6] < othervalue && value[7] < othervalue)
{
othervalue = 100;
simplefunction();
}
else
{
calculatewithallvalues(values);
}
I have noticed that i could probably improve the code. The calculations in the "else" only need to be done if the condition for that specific value is not met. Therefore in certain cases the calculation does not have to be done for every value. I came up with a different approach using a for loop. However, this code is longer an maybe more confusing. The extra if loop at the end is needed to account for the possibility that all values meet the condition.
uint32_t value[8];
uint16_t othervalue;
uint8_t calc_needed = 0;
int i;
for (i=0; i <7; i++)
{
if (value[i] < othervalue)
{
//do nothing
}
else
{
calculatewithvalue(values[i]);
calc_needed = 1;
}
if (calc_needed == 0)
{
othervalue = 100;
simplefunction();
}
Which is the better solution or is there a third solution?
There is a third solution:
for(i=0; i < 7; i++) {
if (value[i] < othervalue ) continue;
break;
}
if (i == 7) { // loop completed; all values were below othervalue
othervalue = 100;
simplefunction();
}
else {
calculatewithallvalues(values);
}

How to represent a loop with a "continue" statement from C in a PlantUML activity diagram

I need to convert C code below to an activity diagram using PlantUML.
What is a good solution to implement the "continue" statement from the code below ?
void function_1(){
int a = 0;
int b =0;
for (int i; i < 8; i++)
{
if (i < 2)
{
continue;
}
if (i > 4)
{
a = 1;
}
else
{
b = 2;
}
}
}
I do not know C but it seems to me that one way of representing your logic in PlantUML would be as follows:
start
while (i < 8 ?)
if (i > 4 ?) then (yes)
:a = 1;
else (no)
if (i >= 2 ?) then (yes)
:b = 2;
else (no)
endif
endif
endwhile (no)
:Carry out the next task;
end
The "Carry out the next task" task is a placeholder. It should be replaced with whatever your application is supposed to do next.
Which yields the following diagramme:
Regardless of converting the code to another language or not, I would optimize it the following way, in the first place:
void function_1(){
int a = 0;
int b =0;
for (int i=0; i < 8; i++)
{
if (i > 4)
{
a = 1;
}
else if ( i >= 2 )
{
b = 2;
}
else
{
/* - nothing to do */
/* - this statement is here as proof that we do not want to handle
/* other cases, as opposed to just forgetting about them */
/* - it can be used in the future for extension, as needed */
}
}
}

In C language, comparing 2 members of a structure

I seem to have trouble with comparing 2 members of a structure.
I can see in watch window that the sequence in all logs are 0x000.
This one evaluates AllLogsNotZero to TRUE
for (i=0;(i<(3)&&(!AllLogsNotZero));i++)
{
UINT8 j;
j=i+1;
UINT16* comp1;
UINT16* comp2;
comp1 = (UINT16*) (&Data.log[i].Sequence);
comp2 = (UINT16*) (&Data.log[j].Sequence);
if ((Data.log[i].Sequence == Data.log[j].Sequence) == 0)
AllLogsNotZero=FALSE;
else
AllLogsNotZero=TRUE;
This one evaluates AllLogsNotZero to FALSE
for (i=0;(i<(3)&&(!AllLogsNotZero));i++)
{
UINT8 j;
j=i+1;
UINT16* comp1;
UINT16* comp2;
comp1 = (UINT16*) (&Data.log[i].Sequence);
comp2 = (UINT16*) (&Data.log[j].Sequence);
if (Data.log[i].Sequence == Data.log[j].Sequence)
AllLogsNotZero=FALSE;
else
AllLogsNotZero=TRUE;
I don't know why.
I think you're making a mountain out of a molehill. I think the way I'd write the loop using your current variable name is:
bool AllLogsNotZero = true;
for (int i = 0; i < 4; i++)
{
if (Data.log[i].Sequence == 0)
{
AllLogsNotZero = false;
break;
}
}
if (AllLogsNotZero)
…processing option for no zero logs
else
…processing option for at least one log zero
We can debate whether the loop limit should be 3 or 4 (or some other value); it isn't entirely clear from your code, but you set j to i+1 and use that, and limit i to < 3, so when the code doesn't use i+1, the limit should probably be 4. It would be better to have an enumeration or #define value for the limit — the name would indicate what you're measuring against better than just the number.
The negative in the name (AllLogsNotZero) also makes life harder; avoid that when you can. For example:
bool LogsZero = false;
for (int i = 0; i < 4; i++)
{
if (Data.log[i].Sequence == 0)
{
LogsZero = true;
break;
}
}
if (LogsZero)
…processing option for at least one log zero
else
…processing option for no zero logs
Look if statements
First check:
//You check if they are the same
if (Data.log[i].Sequence == Data.log[j].Sequence)
Second check
//You check if they are not the same
if ((Data.log[i].Sequence == Data.log[j].Sequence) == 0)
//Can be evaluated as:
if (Data.log[i].Sequence != Data.log[j].Sequence)
for (i=0;(i<(3)&&(!AllLogsNotZero));i++)
{
UINT16 Var1 = 0;
if (Data.log[i].Sequence == Var1)
AllLogsNotZero=FALSE;
else
AllLogsNotZero=TRUE;
This works!!

Varying arguments for if () statement

I have a problem as stated below:
i have an array(say) a[]={10,24,56,33,22,11,21}
i have something like this
for(i=0;i<100;i++){
if(a[i]==10)
// do something
}
next when i=1
if(a[i]==10 && a[i+1]==24)
so on so at each iteration the arguments / conditions within if should be varying
now this will be a very big sequence i cant explicitly write
if(a[i]==10 && a[i+1]==24 && a[i+2]==56 ...... a[i+100]=2322)
how can i achieve this varying conditions?
You have to have a cumulative "boolean" variable that checks a[i] at the i-th iteration and update that variable:
int a[] = {...}; /* array with some values to verify */
int v[] = {...}; /* these are the actual desired values in a[] */
/* the verifying loop */
int i;
int cond = 1;
for (i = 0; i < 100; i++)
{
cond = cond && (a[i] == v[i]);
if (cond)
{
/* do something */
}
}
I think that you should introduce a boolean value.
bool valid = true;
for(i=0;i<100;i++){
if(a[i]==10 && valid)
// do something
else
{
valid = false;
break;
}
}
For every iteration, you need to change the value to which you are comparing a[i]
Have a loop within a loop:
for (i = 0; i != 100; ++i)
{
int condition = 1;
for (j = 0; i + j != 100 && condition; ++j)
{
condition = condition && (a[i + j] == /* your number */ );
}
if (condition) { /* ... */ }
}
In this case, you can use function pointers or blocks.
You can find a good example here here
Seeing your examples, I think that the variations you are talking about is only in the length of array 'a' whose presence you want to check in some array x. If indeed it is so, memcmp can be of use to you.
Let me modify your example a bit to clarify what I am saying.
int a[7]={10,24,56,33,22,11,21} is the required values you want to check in some array 'x', with different lengths of 'a' each time, with 'x' declared as
int x[1000];
In that case, you could use memcmp as follow :-
for ( len = 1 ; len <= 7 ; ++len )
{ for ( i = 0 ; i <= 1000-len ; ++i )
{ if ( ! memcmp( a, x+i, len * sizeof(int) ) )
{ // do something
}
}
}

Resources