What happens inside of this condition statement? while (a = foo(bar)) - c

It may sounds silly, but I want to know the happening when I execute while(a = function(b)){}.
Suppose we got NULL for the return value of read_command_stream.
Can I get out of the loop?
while ((command = read_command_stream (command_stream)))
{
if (print_tree)
{
printf("# %d\n", command_number++);
print_command (command);
}
else
{
last_command = command;
execute_command(command, time_travel);
}
}
struct command
struct command
{
enum command_type type;
// Exit status, or -1 if not known (e.g., because it has not exited yet).
int status;
// I/O redirections, or null if none.
char *input;
char *output;
union
{
// for AND_COMMAND, SEQUENCE_COMMAND, OR_COMMAND, PIPE_COMMAND:
struct command *command[2];
// for SIMPLE_COMMAND:
char **word;
// for SUBSHELL_COMMAND:
struct command *subshell_command;
} u;
};

The syntax says:
while (expression) { ... }
and expression can be a lot.
It can be:
a constant: while (1) { ... }
the result of a comparison: while (a < b) { ... }
some boolean construct: : while (a < b && c < d ) { ... }
the resulting expression from an assignment: while (*dst++ = *src++) {;}
and the assignment can also involve function calls: while((ch = getc()) != EOF) { ... }
a plain variable: while(i) ( ...)
an expression based on the evaluation of a plain variable : while (i--) { ... } (even with side effects!)
a pointer expression: : while (*++argv) { ... }
Now, in the case of an integer expression, the expression is checked for not equal to zero. For pointer expressions, it is checked against not equal to NULL. That's all.
The crux of this is that in C, even an assignment is an expression, so you can write:
a = b = c;
or even:
a = b = c = d;
But, since an assignment is also an expression, you could even write:
while ( a = b = c = d) { ... }

The = evaluates to whatever it sets the variable to, so if you do something like
var = 0
This evaluates to 0 and if it was in a while loop would break out.
Also remember NULL is just 0 (though it's not guaranteed) so something returning NULL will have the same effect to break out of a loop. Generally it's a bad idea to use an = as a condition and good compilers will warn you about it.

Null is supposed to be zero unless otherwise specified on your system/compiler. Therefore, the loop terminates.

Related

while loop with variable definition in C

I'm currently trying to loop over a collection retrieved by an API in C.
The API offers a function getNext() that returns a reference to the next element in the collection, or NULL if the end has been reached.
Now i wanted to declare a variable in a while expression and loop until NULL:
// create collection from API
Collection collection = create();
if (collection == NULL) {
return -1
}
while (const Element *e = getNext(collection) != NULL) {
// print data from e
}
When compiling, 'error: unexpected expression' pops up. Why does that statement not work in C? How can I loop over the collection when all I have is a function getNext() that returns either an element or NULL?
I also tried the following, but the same error occured:
while ((const Element *e = getNext(collection)) != NULL) {
// print data from e
}
It is not possible because while() expects an expression and it is not possible to place a declaration in the expression (though it is possible to introduce a new type with expression!).
The best you can get is:
const Element *e;
while ((e = getNext(collection)) != NULL) {
// print data from e
}
It is however possible to achieve the desired functionlity with a for loop.
for (const Element *e; (e = getNext(collection)) != NULL; ) {
// print data from e
}
First of all, in contrast to a for statement, you cannot declare a new variable in a while statement. Therefore, the following line is wrong:
while (const Element *e = getNext(collection) != NULL) {
You could fix this by writing the following:
const Element *e;
while ( e = getNext(collection) != NULL ) {
A more compact way of writing this is the following:
for ( const Element *e; e = getNext(collection) != NULL ; ) {
The second version has the advantage that the scope of the variable e is limited to the for loop.
However, the lines mentioned above are also wrong, for the following reason:
The != operator has higher precedence than =. So the line
while ( e = getNext(collection) != NULL) {
is equivalent to:
while ( e = ( getNext(collection) != NULL ) ) {
This is not want you want. You should write the following instead:
while ( ( e = getNext(collection) ) != NULL ) {
In C, you can't declare a variable in the condition expression of a while loop.
GCC will tell you:
Error: Expected expression before 'const'
I would write something like this, hope it can help :)
void main()
{
bool running = true;
while(running)
{
printf("Running while loop\n");
running = getNext() != NULL; //Check if there is data in your collection - otherwise exit
}
printf("getNext() returned NULL\n");
return;
}
Some rules of thumb in C programming are: "don't do really strange things" and "never do assignments inside control or loop statements". Turns out that we can follow these rules and solve all problems by using a for loop:
for(const Element* e = getNext(collection); e != NULL; e = getNext(collection))

Will an If inside An If always be read? Not nested, but put right in front of the last one

The second if is always executing, no matter what the values from the first one was, I´m comparing char arrays from a struct.
Tried doing all of the comparisons in one If, like this:
if(strcmp(t[j].NomePeca, t[n].NomePeca) == 0 && strcmp(t[j].nroPoltrona, t[n].nroPoltrona) == 0 && strcmp(t[j].hora, t[n].hora) == 0 && strcmp(t[j].data,t[n].data) == 0) { ... }
Same thing.
struct TabelaIngresso {
char NomePeca[30];
char data[10];
char hora[5];
int aPagar;
char nroPoltrona[3];
};
// ............................
if (strcmp(t[j].NomePeca, t[n].NomePeca) == 0 && strcmp(t[j].nroPoltrona, t[n].nroPoltrona) == 0) {
if((strcmp(t[j].hora,t[n].hora) == 0) && (strcmp(t[j].data,t[n].data) == 0)) {
anulado = 1;
printf("\nCompra anulada pois a poltrona nao esta disponivel!\n");
strcpy (t[j].NomePeca, "Anulado");
strcpy (t[j].data, "Anulado");
strcpy (t[j].hora, "Anulado");
t[j].nroPoltrona[3] = '0';
t[j].aPagar = 0;
}
}
This If should only be executed if all of the strings are the same.
You might be asking about behavior called Short-circuit evaluation. It is the default behavior of the majority of the commonly used programming languages. The idea is that in a boolean expression the next argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression. Have a look at the example:
function foo() {
console.log('foo');
return false;
}
function bar() {
console.log('bar');
return true;
}
if (foo() && bar()) {
console.log('bar() will not ever be called');
} else {
console.log('calling foo() is enough');
}
The code above is equivalent to:
const bool = && bar();
if (foo()) {
if (bar()) {
console.log('bar() will not ever be called');
}
} else if (!bar()) {
console.log('calling foo() is enough');
}
But it's much easier to read the code from the first snippet.

Can't check return value of a function in C

So I'm trying to check my functions return value in an if statement so that i can check wheter it's working fine or not.
I have:
if (int r = (input(num_first, num_second, fixPTR)) =! -1)
{
// do smth
}
but Visual Studio says : expression must be a modifiable lvalue
how do i fix it??
You need to declare your variables before your code.
And the syntax for the opposite of == is != and not =! by the way.
int r;
if ((r = input(num_first, num_second, fixPTR)) != -1)
{
// do smth
}

parsing with recursion - brackets

Could some give me a hint at this problem :
An expression is correct only if it contains parentheses and braces properly closed and no other character, even space. For example, () ({} () ({})) is a correct expression, whereas ({)} is not a correct expression or {} ({})). An empty expression (which does not contain any character) is correct.
Given a string expression determine if the expressions is correct and if is determine the maximum level of nesting. Maximum level of nesting parentheses is the maximum number of one another.
Examples
{}({}){{(({}))}}
answer : 5
{}({})) -1 (because the expression is incorrect)
That's what I've did so far.
#include <stdio.h>
#include <stdlib.h>
FILE *fi, *fo;
int first, er;
void X();
void Y();
void S() {
X();
Y();
}
void X() {
if(first=='{') {
first=fgetc(fi);
X();
if(first=='}')
first=fgetc(fi);
else
er=1;
S();
}
}
void Y() {
if(first=='(') {
first=fgetc(fi);
Y();
if(first==')')
first=fgetc(fi);
else
er=1;
S();
}
}
int main()
{
fi = fopen("brackets.in","r");
fo = fopen("brackets.out","w");
first=fgetc(fi);
S();
if(first!='\n')
er=-1;
fprintf(fo,"%d",er);
fclose(fi);
fclose(fo);
return 0;
}
First off, it helps to think of your problem as a formal grammar.
S = The Language you are testing for
S->
NUL // Empty
SS // S followed by itself.
[ S ] // Case 1
( S ) // Case 2
{ S } // Case 3
Since this grammar only has one symbol (S), you only need one parsing method.
The following code is incomplete but hopefully it gets the idea across.
char curr_char;
int main (void)
{
curr_char = getc();
result = parse_s();
return 0;
}
// Parse the S pattern off input. When this method completes, curr_char points to the character AFTER S.
// Returns recursion count or -1 on fail.
int parse_s()
{
max_count = 0;
while(true)
{
int curr_count = 0;
switch 'curr_char':
{
case '[': // [
int count = parse_s(); // S
if (count == -1) return -1; // The S must be valid
if (curr_char != ']') return -1; // ]
curr_char = getc(); // Advance past the ]
curr_count = count + 1; // This expression is 1 nest greater than its contained S
break;
case '(':
// XXX
break;
case '{':
// XXX
break;
default:
// This is either the SS (find the max of the two), the NUL case (return 0), or an error (return -1)
break;
}
// In the SS case you're gonna have to loop and do something here.
}
return max_count;
}

Arithmetical operations in certain script language

I am working on certain script language. Values containing structure is
struct myvar
{
char name[NAMELEN];
int type;
void* value;
}
type = 0 --> int* value
type = 1 --> char* value
type = 2 --> float* value
I faced some problem with arithmetic operations. It seems that I need to commit all sorts of type conversions over every single operation, that develops into writing a whole bunch of code for each of them, as in:
case 0: // "="
if(factor1.name)
{
if((factor1.type == 1) && (factor2.type==1))
{
free(factor1.value);
int len = (strlen((STRING)factor2.value)+1)*sizeof(char);
factor1.value = malloc(len);
memcpy(factor1.value,factor2.value,len);
}
else if((factor1.type == 2) && (factor2.type==2))
*(FLOAT*)factor1.value = *(FLOAT*)factor2.value;
else if((factor1.type == 0) && (factor2.type==0))
*(INTEGER*)factor1.value = *(INTEGER*)factor2.value;
else if((factor1.type == 0) && (factor2.type==2))
*(INTEGER*)factor1.value = *(FLOAT*)factor2.value;
else if((factor1.type == 2) && (factor2.type==0))
*(FLOAT*)factor1.value = *(INTEGER*)factor2.value;
else
GetNextWord("error");
}
break;
Is there some way to avoid this tiresome procedure? Otherwise I have no choice but to copy-paste this piece of code for each of "=","~","+","-","*","/","%",">","<",">=","<=","==","~=","AND","OR"
Use a union instead of a struct for the values:
struct myvar {
enum {
STRING, INT, FLOAT,
} type;
union {
char strval[NAMELEN];
int intval;
float fltval;
} val;
};
and then in executing the assignment operator in your scripting language you just do:
factor1 = factor2;
To fetch the right value based on the type you would do:
switch (operand.type) {
case STRING:
printf("%s", operand.val.strval);
break;
case INT:
printf("%d", operand.val.intval);
break;
case FLOAT:
printf("%f", operand.val.fltval);
break;
}
What about writing 3 toType functions:
char* toType0(myvar* from)
{
if (from->type == 0) return (char*)(from->value);
else if (from->type == 1) return itoa((int*)from->value);
else...
}
int toType1(myvar* from)
{
//convert to int...
}
Then in your conversion routines you can do:
switch (factor1.type)
{
case 0:
{ char* other = toType0(&factor2);
//assign or add or whatever....
};
break;
case 1:
{ int other = toType1(&factor2);
//assign or add or whatever....
};
break;
...
}
I would propose the following: when applying an operation, you should first coerce the operand types. E.g., if your operand types are int and float, you should coerce int value to a float one, and continue with the float version of the operation. The coercion is the same (or almost the same) for all the operations. With such an approach, you have much less cases to consider.

Resources