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))
Related
I'm writing an auto display turn-off function with ESP32 on Arduino framework with PIO.
I have a Screen class for handling all of the screen functions.
void Screen::turn_off_screen(){
digitalWrite(SCREEN_ENABLE, LOW);
}
void turn_off_screen_wrapper()
{
Serial.println("turn_off_screen_wrapper called");
if (c_screen_Instance != nullptr)
{
c_screen_Instance->turn_off_screen();
}
}
void Screen::auto_display_power_off(int timeout){
Serial.println("auto_display_power_off called");
c_screen_Instance = this;
auto_off_timer = timerBegin(0, 80, true);
Serial.println("auto_off_timer ran");
timerAttachInterrupt(auto_off_timer, &turn_off_screen_wrapper, true);
Serial.println("timerAttachInterrupt ran");
//Converts given seconds from us to seconds
timerAlarmWrite(auto_off_timer,timeout*1000000,false);
timerAlarmEnable(auto_off_timer);
}
The code compiles however I get this when I run it on the board.
auto_display_power_off called
[E][esp32-hal-cpu.c:93] addApbChangeCallback(): duplicate func=400811F8 arg=3FFBDC54
auto_off_timer ran
The screen never gets turned off of course since the callback never runs. Any ideas why this is happening?
is c_screen_Instance global?
is auto_off_timer global?
Consider providing a bit more of your code.
But anyway.
bool addApbChangeCallback(void * arg, apb_change_cb_t cb){
initApbChangeCallback();
apb_change_t * c = (apb_change_t*)malloc(sizeof(apb_change_t));
if(!c){
log_e("Callback Object Malloc Failed");
return false;
}
c->next = NULL;
c->prev = NULL;
c->arg = arg;
c->cb = cb;
xSemaphoreTake(apb_change_lock, portMAX_DELAY);
if(apb_change_callbacks == NULL){
apb_change_callbacks = c;
} else {
apb_change_t * r = apb_change_callbacks;
// look for duplicate callbacks
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
if (r) {
log_e("duplicate func=%8p arg=%8p",c->cb,c->arg);
free(c);
xSemaphoreGive(apb_change_lock);
return false;
}
else {
c->next = apb_change_callbacks;
apb_change_callbacks-> prev = c;
apb_change_callbacks = c;
}
}
xSemaphoreGive(apb_change_lock);
return true;
}
This is addApbChangeCallback's declaration.
Your error comes from this line :
while( (r != NULL ) && !((r->cb == cb) && ( r->arg == arg))) r = r->next;
Where r it's a struct to hold all the callbacks.
This error indeed indicates this callback function was already assigned somewhere in your code. r is global, so your code is re-assigning the same callback twice.
Try to either only assign it once, or to unassign the function before assigning it again with removeApbChangeCallback(void * arg, apb_change_cb_t cb) or timerDetachInterrupt
I've also found a reported issue related to timerAttach on the current version here: https://github.com/espressif/arduino-esp32/issues/6730
Try to roll back the Platform PIO's version to a more stable one:
# instead of espressif32
platform = https://github.com/platformio/platform-espressif32.git#<tag-version>
Check on the git link for the available tags you can use.
Problem was that I was attaching the interrupt in the void loop(). Which would run way faster than the actual timer. After moving it to setup (Setup being a placeholder) I plan on having it on a Hardware interrupt it worked as expected.
This question already has answers here:
Changing address contained by pointer using function
(5 answers)
Does using calloc inside function, change the pointer passed as function argument
(2 answers)
Closed 5 years ago.
I am working with linked list in C, but I think didn't understant very well the use of pointers.
I have a structure for my linked list. I initialize the first element to NULL. I send this pointer to a function to create (with malloc) a new element of the list. But after the call of the function my element is still NULL. I don't understand. It is surely a stupid error but I need some help..
typedef struct Goto Goto;
struct Goto
{
int index;
Goto *next;
};
//my code
Goto* gotoList = NULL;
addLabel(gotoList, index);
// Here : gotoList is NULL
void addLabel(Goto* gotoList, int value) {
if (gotoList == NULL) {
Goto* gotoLabel = malloc(sizeof(*gotoList));
gotoLabel->index = value;
gotoLabel->next = NULL;
gotoList = gotoLabel;
}
else {
Goto* gotoLabel = gotoList;
Goto* newLabel = malloc(sizeof(*newLabel));
newLabel->next = NULL;
newLabel->index = value;
while (gotoLabel->next != NULL) {
gotoLabel = gotoLabel->next;
}
gotoLabel->next = newLabel;
}
// Here : gotoList is not NULL
}
Thanks for helping me
Well to make change either you have to pass the address of the variable from the caller function or return from the callee function the address of the allocated memory and assign it to respective variable.
Here you do neither of it so you don't get to retain the change.
By passing the adress of the variable you can do it like this:(The other can be done easily if you understand this one fully).
void addLabel(Goto** gotoList, int value) {
if (*gotoList == NULL) {
Goto* gotoLabel = malloc(sizeof(*gotoLabel ));
gotoLabel->index = value;
gotoLabel->next = NULL;
*gotoList = gotoLabel;
}
else {
Goto* gotoLabel = *gotoList;
Goto* newLabel = malloc(sizeof(*newLabel));
newLabel->next = NULL;
newLabel->index = value;
while (gotoLabel->next != NULL) {
gotoLabel = gotoLabel->next;
}
gotoLabel->next = newLabel;
}
}
Here what we did is simply passed the address of the variable. You will call the function like this
addLabel(&listhead,val);
One thing, you have a bad choice in selecting the names of the variables. Goto is the last choice of variable name. In C goto is a keyword, naming a variable on some variation of it is not only misleading but also erroneous in meaning too.
as mentioned in the titled, my function doesn't end well. I am trying to do the following :
" Implement, with the DC method, a function which has this interface :
Returns the majority element of the given sequence if one such exists
PARAMETERS
sequence Valid pointer to an array of elements
sequenceLength Size of the array
*
RETURN
element A pointer to one element corresponding to the majority
element or NULL if no such element exists
const Element getMajElDC(const Element* const * sequence, size_t sequenceLength); "
Actually, I just tried to implement this solution : http://www.ece.northwestern.edu/~dda902/336/hw4-sol.pdf
And here's my way to do it :
const Element* getMajElDC(const Element* const * sequence, size_t,sequenceLength){
printf("1\n");
const Element* element_tmp_right;
const Element* element_tmp_left;
int occurence_left = 0;
int occurence_right = 0;
if (sequenceLength == 1)
return sequence[1];
int mid = (int)sequenceLength/2;
element_tmp_left = getMajElDC(sequence,mid);
if (sequenceLength%2 == 0)
element_tmp_right = getMajElDC(&sequence[mid],mid);
element_tmp_right = getMajElDC(&sequence[mid],mid+1);
if (element_tmp_left == NULL && element_tmp_right != NULL)
return element_tmp_right;
if (element_tmp_right == NULL && element_tmp_left != NULL)
return element_tmp_left;
if (element_tmp_right == NULL && element_tmp_left == NULL)
return NULL;
if (areEqual(element_tmp_left,element_tmp_right))
return element_tmp_left;
for (int i=0;i<sequenceLength;i++){
if( areEqual(sequence[i],element_tmp_left))
occurence_left++;
if (areEqual(sequence[i],element_tmp_right))
occurence_right++;
}
if (occurence_left > mid+1)
return element_tmp_left;
else if (occurence_left > mid+1)
return element_tmp_left;
else
return NULL;
}
When I try to run it in codeblocks, the .exe just stopworking. Just like if the function was endless. That's why I placed a printf in the beginning : I wanted to see how many times the " 1 " would appear in the application windows and it appears so many times that everything goes crazy.
I tried to look into the base case of the recursion, but nothing seems wrong with it...
I am truly lost my poor knowledge of C, does anyone see where the problem is ?
Ps : the areEqual() function is just a given function, here's its implementation but there is nothing special with it :
bool areEqual(const Element* a, const Element* b)
{
return a->value == b->value;
}
with
struct element_t
{
int value;
};
typedef struct element_t Element;
To end my question, I tell you in advance that I'm sorry if a crucial information is missing : It is the first time I use this website, please be indulgent !
You have to use debugger it will show you immediately where the problem is.
BTW look closer this code:
if (sequenceLength == 1)
return sequence[1];
int mid = (int)sequenceLength/2;
element_tmp_left = getMajElDC(sequence,mid);
if (sequenceLength%2 == 0)
element_tmp_right = getMajElDC(&sequence[mid],mid);
element_tmp_right = getMajElDC(&sequence[mid],mid+1);
You close the recursion when sequenceLength == 1, but if getMajElDC has been called with sequenceLength=0 it will never return.
Consider to modify:
if (sequenceLength == 1)
return sequence[1];
to:
if (sequenceLength <= 1)
return sequence[1];
consider this code snippet:
int mid = (int)sequenceLength/2;
element_tmp_left = getMajElDC(sequence,mid);
if (sequenceLength%2 == 0)
element_tmp_right = getMajElDC(&sequence[mid],mid);
element_tmp_right = getMajElDC(&sequence[mid],mid+1);
notice that the third call to getMajElDC is always called regardless of the value of sequenceLength. I suspect that you wanted to write this:
if (sequenceLength%2 == 0)
element_tmp_right = getMajElDC(&sequence[mid],mid);
else
element_tmp_right = getMajElDC(&sequence[mid],mid+1);
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
}
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.