Variable Persistence in Linked List - c

I'm making a domino game and when the user adds a domino to the left, the domino is added but when the function exits the domino added is GONE.
FYI:
fitxesJoc (Link List) contains the dominoes of
the game and is a pointer passed to the function (so that it lasts all the game)
opcionesCorrectas (Domino) contains the correct choices of domino
inferior (int) contains the smaller number of the domino
superior (int) contains the bigger number of the domino
pos (int) the position of the domino
opcionFitxa (int) contains the choice of the player
ultimaFitxa->seg is the 'next' node
tNode* ultimaFitxa = (tNode *)malloc(sizeof(tNode));
ultimaFitxa->info.inferior = opcionesCorrectas[opcionFitxa - 1].inferior;
ultimaFitxa->info.superior = opcionesCorrectas[opcionFitxa - 1].superior;
ultimaFitxa->info.pos = opcionesCorrectas[opcionFitxa - 1].pos;
ultimaFitxa->seg = fitxesJoc;
fitxesJoc = ultimaFitxa;
Header of the function
unsigned int demanar_fitxa_tirar(tJugador *jugador, tNode* fitxesJoc, tPartida *partida, tPila* fitxesBarrejades, bool primerCop)
Call of the function
resultado = demanar_fitxa_tirar(&Jugadors[jugadorActual], fitxesJoc, partida, fitxesBarrejades, true);
This way I add the domino, in the top of the other dominoes.

Your problem is that the last line of demanar_fitxa_tirar:
fitxesJoc = ultimaFitxa;
is assigning to a local variable, which has no effect on the calling code. You need to pass a pointer to the calling code's fitxesJoc, like this:
unsigned int demanar_fitxa_tirar(..., tNode** fitxesJoc, ...) // Note extra *
{
// ...
*fitxesJoc = ultimaFitxa; // Note extra *
}
void mainProgram()
{
tNode* fitxesJoc;
// ...
resultado = demanar_fitxa_tirar(..., &fitxesJoc, ...); // Note extra &
// ...
}

From your code, it's not clear where your function starts and ends and what it takes as parameters but I guess your problem is with the fitxesJoc variable which is probably passed as an argument to the function. C copies arguments when calling functions (call-by-value). You could pass the address to fitxesJoc variable using a pointer instead and rewrite it as something like this:
// fitxesJoc would be a `tNode**` rather than `tNode*`.
tNode* ultimaFitxa = (tNode *)malloc(sizeof(tNode));
ultimaFitxa->info.inferior = opcionesCorrectas[opcionFitxa - 1].inferior;
ultimaFitxa->info.superior = opcionesCorrectas[opcionFitxa - 1].superior;
ultimaFitxa->info.pos = opcionesCorrectas[opcionFitxa - 1].pos;
ultimaFitxa->seg = *fitxesJoc;
*fitxesJoc = ultimaFitxa;

I don't think you've provided enough code, but I suspect the problem is in:
fitxesJoc = ultimaFitxa;
(Linked-list now equals the new Node).
The problem is that parameters are passed by value.
If you want to change the value of the parameter, you'll need to pass by pointer,
and use the pointer to change the value.
*pfitxesJoc = ultimaFitxa;
Please provide more code, including the function header and the function call, for a better answer.

It looks like you're not actually adding the new domino to the linked list. But, it's hard to tell because you need to post more code, and because your code isn't in English.

Related

How to define the callback for an esp32 arduino ble scan result

The definition to start a BLE scan is:
bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults), bool is_continue = false);
The second parameter seems to be the callback when a scan is complete, being somewhat new to this Im unsure how to define it.
fwiw Ive tried this:
void OnScanResults(BLEScanResults scanResults)
{ }
and used it like this:
scanResults = scan->start(60, OnScanResults, true);
but obvious to others, that didnt work.
Please help me decypher that signature
void (*scanCompleteCB)(BLEScanResults)
you need to add & to OnScanResults because:
void (*scanCompleteCB)(BLEScanResults)
is a pointer to a function which takes a BLEScanResults, returns nothing and is called scanCompleteCB
So your call should be:
scanResults = scan->start(60, &OnScanResults, true);
just as a pointer to a int points to the address of a int
int pointedTo;
int* ptr = &pointedTo;

ocaml c interop passing struct

I hit weird case when trying to call c from ocaml.
This is the c side of things:
typedef struct {
TSNode node;
} AstNode;
CAMLprim value caml_ts_document_root_node(value document) {
CAMLparam1(document);
TSNode root_node = ts_document_root_node(document);
AstNode elNode;
elNode.node = root_node;
CAMLreturn(&elNode);
}
CAMLprim value caml_ts_node_string(value node) {
CAMLparam1(node)
CAMLlocal1(mls);
AstNode* n = (AstNode*) node;
char *s = ts_node_string(n->node);
mls = caml_copy_string(s);
CAMLreturn(mls);
}
On the ocaml side
type ts_point
type ts_document
external ts_node_string : ts_node -> string = "caml_ts_node_string"
external ts_document_root_node : ts_document -> ts_node = "caml_ts_document_root_node"
If you see the code, I'm wrapping in caml_ts_document_root_node the TSNode root_node = ts_document_root_node(document); in an extra defined struct AstNode.
When I write the following implementation however:
CAMLprim value caml_ts_document_root_node(value document) {
CAMLparam1(document);
TSNode root_node = ts_document_root_node(document);
CAMLreturn(&root_node);
}
My code segfaults when calling caml_ts_node_string on the returned node by caml_ts_document_root_node.
Does anyone have any hints on why the segfault appears when I don't wrap a TSNode in an extra struct when interoping from ocaml?
That's definitely not the right usage of the foreign interface! You can't just take a value and cast it to OCaml value. OCaml values are specially encoded, even integers, and have a different representation than C values.
If you want to encode a C value as an OCaml value, you shall use custom values.
First of all, you need to implement the interface of a custom value, fortunately, you can rely on defaults for that:
static struct custom_operations ast_ops = {
"ast_node",
custom_finalize_default
custom_compare_default,
custom_hash_default,
custom_serialize_default,
custom_deserialize_default,
custom_compare_ext_default
};
Next, you need to learn how to allocate custom blocks. For example, the following call will allocate the new AstNode in the OCaml heap:
res = caml_alloc_custom(&ast_ops, sizeof(AstNode), 0, 1);
To access the value itself, you need to use the Data_custom_val macro, e.g.,
if (res) {
AstNode *node = Data_custom_val(res);
TsNode *tsnode = res->node;
}
The complete example of a correct (I hope) implementation of your first function is below:
CAMLprim value caml_ts_document_root_node(value document) {
CAMLparam1(document);
CAMLlocal1(res);
res = caml_alloc_custom(&ast_ops, sizeof(AstNodes), 0, 1);
if (res) {
AstNode *ast = (AstNode *)Data_custom_val(res);
ast->node = ts_document_root_node(document);
}
CAMLreturn(res);
}
As you may see, this is not trivial and rather low-level. Though nothing really magical, especially after you've read the corresponding parts of the OCaml documentation. However, it is much easier to use the CTypes library, that hides most of those complexities and allows you to call C function directly from OCaml
This seems to be unrelated to the ocaml interop part; you are returning the address of a local variable in this function:
CAMLprim value caml_ts_document_root_node(value document) {
// ...
AstNode elNode;
// ...
CAMLreturn(&elNode);
}
When it returns, the (stack) memory it refers to is invalid (in the sense that it will be reused at the next function call).

C Programming - fprintf and printf in while cicle doesn't work

I'm getting a strange problem with a while cicle inside of a function.
I have to look for the extreme vertices of a .ply model. All the data is stored in a linked list. When I'm done creating the list, I call the findExtremeVertex function, that modifies 6 global variables (leftVertex, rightVertex, downwardVertex, upwardVertex, backVertex and frontVertex).
To see if the values are right (the models I use are a bit too big to control every single line to find the maximum of every vertex) I decided to print every change in the max-min values but, when I try to print them in a file, the file is empty. Why is that? Also, when I saw that the file was empty, I tried to print something directly in the console but that didn't work either.
Here's the code of the funcion:
void findExtremeVertex(Vertex *vertex){
FILE *modelInfoFile;
int i = 0;
///Giving data to direction-vertices pointers
leftVertex = malloc(sizeof(Vertex));
rightVertex = malloc(sizeof(Vertex));
upwardVertex = malloc(sizeof(Vertex));
downwardVertex = malloc(sizeof(Vertex));
frontVertex = malloc(sizeof(Vertex));
backVertex = malloc(sizeof(Vertex));
///Giving the direction-vertices the values of the parameter
leftVertex = vertex;
rightVertex = vertex;
upwardVertex = vertex;
downwardVertex = vertex;
frontVertex = vertex;
backVertex = vertex;
///Opening file
modelInfoFile = fopen(us2, "w");
if(modelInfoFile == NULL){
printf("Error in file opening. Exiting.");
exit(EXIT_FAILURE);
}
///Scrolling the list
while(vertex->prev != NULL){
vertex = vertex->prev;
///If the given element of the list is more to the right than the global variable,
///I assign the values of the element to the global variable
if(vertex->vertexCoordinates.x > rightVertex->vertexCoordinates.x){
rightVertex = vertex;
}
/**
I'm omitting the other if constructs because are basically
the same, but the syntax is correct
**/
///Printing in file the cycle information
fprintf(modelInfoFile, "********** CYCLE %d **********\n\n", i);
fprintf(modelInfoFile, "Vertex sx\n");
fprintf(modelInfoFile, "%1.4f %1.4f %1.4f %1.4f %1.4f %1.4f\n\n", leftVertex->vertexCoordinates.x,
leftVertex->vertexCoordinates.y,
leftVertex->vertexCoordinates.z,
leftVertex->vertexNormals.x,
leftVertex->vertexNormals.y,
leftVertex->vertexNormals.z);
/**
Again, I'm omitting some repetitions but the syntax is correct
**/
}
}
I call this function in another function, but there's no segmentation fault signal, the compiler doesn't tell me anything, the program doesn't crash. I have no clue of the error, except from the fact that the file where I print the infos about the cycles is empty. What am I doing wrong?
There are many problems in your code.
You malloc() 6 variables and never use any of them, and you don't check if malloc() succeeded.
You never call fclose() or fflush() so maybe you are seeing the file before the data is flushed to the disk.
You reassign all the *Vertex (except for rightVertex) variables after they are malloc()ed to the same pointer vertex which means
You are causing a memory leak.
You are using 6 variables for a single pointer.
All the *Vertex variables are not declared inside the function which means that they are in the global scope, that is very likely a bad design choice. Given the code you posted it's not possible to tell whether or not global variables are the right choice, but 99% of the time they are a bad choice and there is a much more elegant and safe way to do things.
The bold point above is likely the reason why your program is behaving as it is.
The code
leftVertex = vertex;
rightVertex = vertex;
upwardVertex = vertex;
downwardVertex = vertex;
frontVertex = vertex;
backVertex = vertex;
sets the pointer value but not the actual value. You malloc space, get a pointer to that space, and then throw that pointer away setting it to the pointer of virtex.
Do you mean to use
*leftVertex = *vertex;
*rightVertex = *vertex;
*upwardVertex = *vertex;
*downwardVertex = *vertex;
*frontVertex = *vertex;
*backVertex = *vertex;
///Scrolling the list
while(vertex->prev != NULL){
vertex = vertex->prev;
And what happens if vertex is NULL after this?
You're checking if it's NULL, then changing it's value such that it can become NULL.
///Opening file
if(modelInfoFile == NULL){
printf("Error in file opening. Exiting.");
exit(EXIT_FAILURE);
}
I don't see you opening file.
if((modelInfoFile=fopen(filename,"w")) == NULL){
Should work.
EDIT
In you while loop you change -
vertex = vertex->prev;
But in fprintf you store in file in value of leftVertex->vertexCoordinates.x
So how do you expect to print inside file correctly.

strcpy() does not write new string

In my code, I want to update the contents of global array data via a function. When I call the function, however, the contents of data do not change, despite the function calling strcpy() to effect that change -- afterward, data still contains "prg". How can I use strcpy() or something similar to write a new value to data?
char data[255] = "prg";
void process_tuple(Tuple *t)
{
//Get key
int key = t->key;
//Get integer value, if present
int value = t->value->int32;
//Get string value, if present
char string_value[32];
strcpy(string_value, t->value->cstring);
strcpy(data, "prg1212");
//Decide what to do
switch(key) {
case key_0:
break;
};
}
static WeatherAppDataPoint s_data_points[] =
{
{
.city = data,
.description = "surfboard :)",
.icon = WEATHER_APP_ICON_GENERIC_WEATHER,
.current = 110,
.high = 120,
.low = 100,
},
};
You are mistaking, the program as written will change data to prg1212 if the function is executed. You are either not calling it (bad event hookup, etc), the code as written isn't accurate (partial code that hides the real problem) or evaluating the wrong pointer during debugging (or at the wrong time).
I have figured out the problem with help from #Blidny and #MikeofSST
It turns out that my code above contained in a file app_data.c wasn't running code outside if the functions created in app_data.h. I moved my code up into the void where my temperature values were formatted and written, and strcpy() worked like a charm.

Using pthread_create

I am having errors when I try to use pthread_create. I understand that my use of argsRight->thread_id / argsLeft->thread_id and NULL are not correct, but I am unsure how else to make a reference to the thread id. It requires a pointer, but it seems like every way I tried (&, *), the GCC compiler would not accept.
Also, is there any reason it will not accept my use of NULL? I can't see any reason that would be wrong, but GCC says my use of the void function is invalid.
Can anyone shed some light on how to properly set up a call to pthread_create? I have included parts from my method where I am using the pthread_create function.
void pthreads_ms(struct ms_args* args)
{
int left_end = (args->end + args->start) / 2;
int right_start = left_end + 1;
int rc1, rc2;
// Create left side struct
struct ms_args* argsLeft;
argsLeft = malloc(sizeof(args));
argsLeft->thread_id = (2 * args->thread_id + 1);
argsLeft->start = args->start;
argsLeft->end = left_end;
argsLeft->array = args->array;
// Same methodology as above to create the right side
if (args->start != args->end)
{
// Print the thread id number, and start and end places
printf("[%d] start %d end %d", args->thread_id, args->start, args->end);
// Sort Left Side
rc1 = pthread_create(argsLeft->thread_id, NULL, pthreads_ms(argsLeft), argsLeft); //problem line here
//Sort right side
rc2 = pthread_create(argsRight->thread_id, NULL, pthreads_ms(argsRight), argsRight); //problem line here
}
It is not your application, it's pthread_create() will fill thread_id field. So, first of all, struct ms_args's field should be of type pthread_t and you should pass a pointer to that field:
pthread_create(&argsLeft->thread_id, ...
According to pthread_create the proper call should be
rc1 = pthread_create(&(argsLeft->thread_id), NULL, &pthreads_ms, argsLeft);
Same goes for right side.
The definition of pthread_ms() should include a return value
void *pthreads_ms(struct ms_args* args) { ... }
Besides that, your code looks pretty dangerous to me, since it creates recursively two threads for every existing one. Depending on your input, this might build a large tree of threads, which could bring your system to a halt.

Resources