I have a problem of declaring a global scope pointer, in the definition part of my flex file, then i malloc it in the start of my main, but as soon as my program runs into yylex(), the pointer's value is set to NULL.
I need this pointer to a struct (this is struct Modele * model) all along my program, it's basically a pointer to the structure I store all my results from the file in, so I actually cannot do without it, at least not without a pointer to a struct which would work fine in both main() and yylex().
On execution, the program runs into a segfault, trying to write at the adress 0x4 ; running the program under valgrind, and printing the value of model allowed me to understand that the memory was correctly allocated, but as soon as yylex was called, the value of model was NULL (printed (nil)). I don't use any header here, but i tried using one to store all my structures, and the declaration of my global scope variables, but without success.
My question is : what did I do wrong to face such a behavior ? And what is generally the best way not to have this problem ? I'm not sure I ever used global scope pointers, so it could be this, or maybe a flex-lex specific problem .... i'm a bit lost !
Here is a sample of my code :
%{
#include <stdlib.h>
#include <stdio.h>
//some more includes and #defines
typedef struct Doc {
int classe;
uint32_t * words;
int current_index;
int current_size;
} doc;
typedef struct Modele {
int nb_classes;
int nb_docs;
int nb_docs_base;
int nb_docs_test;
int base_or_test;
int voc_size;
int M_test_size;
liste ** M_theta;
row_info * M_calc;
doc * M_test;
} modele;
//some more typedefs
modele * model; // <--- this is the pointer i talk about
//some more functions bodies .....
%}
couple_entiers [0-9]+:[0-9]+
// .......
%%
{couple_entiers} { model->nb_docs ++}
//.....
%%
int main (int argc, char ** argv)
{
// .....
modele * model = malloc(sizeof model); // <---- here is the malloc
model->nb_classes = 0;
model->nb_docs = 0;
model->nb_docs_base = 0;
model->nb_docs_test = 0;
model->voc_size = 0;
model->M_test = malloc (TAB_SIZE * sizeof(doc));
//....
if ((yyin = fopen(argv[1],"r")) == NULL){
printf("Impossible d'ouvrir %s !\n",argv[1]);
exit(0);
}
yylex();
In case that piece of code is not enough to grab the origin of the problem, i'll paste more of it, I just wanted to select the relevant parts.
My question is : what did I do wrong to face such a behavior ?
You never did set the file-scope variable. Your main() function instead declares and initializes a local variable of the same name and type. The local declaration "shadows" the file-scope one within its scope.
To fix it, just change this ...
modele * model = malloc(sizeof model);
... to this:
model = malloc(sizeof model);
If you do not precede the variable name with a type then you are referring to a variable declared elsewhere (in this case, at file scope).
Related
I was working on the following as an example to see the differences between passing an object directly and then passing a pointer to it:
#include "stdio.h"
// Car object
typedef struct Car {
char* name;
unsigned int price;
} Car;
void print_car(Car car) {
printf("<Car: %s, Price: $%d>", car.name, car.price);
};
void print_car2(Car *car) {
printf("<Car: %s, Price: $%d>", car->name, car->price);
};
int main(int argc, char* argv[]) {
Car chevy = {chevy.name = "Chevy", chevy.price = 45000};
print_car(chevy);
Car mazda = {chevy.name = "Mazda", chevy.price = 30000};
print_car2(&mazda);
return 1;
}
Other than the first approach being much more readable and easier to understand for me, what are the differences between the two? When would passing a pointer be the only option, and why do both work in the above case?
There are two reasons to use the second approach:
If you want to avoid copying the whole struct. If the struct is big, this can affect performance.
If you want to modify struct that you're passing.
In general (not only for structs) passing a variable to a function will make a copy of this variable so if you want to alter this variable you ll have to return the value of the altered copy but you may want to alter the variable and return something else, in this case you have no other choice of passing a pointer as argument exemple :
first exemple with passing a variable
int useless_func(int nb) /*nb is actually a copy of the variable passed as argument */
{
nb++; /* the copy was incremented, not the real variable */
return nb; /* the new value is returned */
}
int main()
{
int nb = 1;
useless_func(nb); /* here nb is still = 1 cause it wasn't altered by the function */
nb = useless_func(nb); /* here nb is = 2 cause it took the return value of the func */
}
now a second stupid exemple with pointer :
char *useless_func(int *nb) /* nb is now a pointer to the variable */
{
*nb++; /* the derefencement of the pointer (so the variable value) was incremented */
return strdup("This is a useless return"); /* we return some other stupid stuff */
}
int main()
{
int nb = 1;
char *str = useless_func(&nb); /* now nb is = 2 and str is an allocated useless string woohoo */
}
When a function is called, the arguments in a function can be passed by value or passed by reference.
void print_car(Car car)
In here you are directly passing an object to the function, that means it will be copied into the functions stack and destroyed after function call ends. This method should be avoided because copying is expensive and unnecessary. Also if your objects are quite big, this operation will take a lot of time
void print_car2(Car *car) {
In this situation you are passing a pointer to the object which is called pass by reference, that means you are working with the original object and changes you make will directly affect it. It's a lot faster because you are not moving your object, but you should be careful about alter of original data
I do not understand why i have to initialize my structure before using it, i get this error in my code, i know it works if i use pointers or if i initialize the structure members, but why it does not work in this way ?
#include <stdio.h>
typedef struct human{
char name[20];
int age;
} student;
void function(student ){
printf("It's not working");
}
int main(){
student a;
function(a);
return 0;
}
I get this
Debug Error!
File: Run - Time Check Failure #3 - The variable 'a' is being used without being initialized. (Press Retry to debug the application)
and i do not get the message from my function on output
You get this error, because your debugger detect, that you are sending unitialized variable to the function. It doesn't know, what will you do with it inside of the function, so it warns you. You can see, that if you run program in release, no error will occur. Easiest solution for you, if you know, that you will initialize it lately to correct values, is just to initialize it, when creating student a = {0};
You are passing the object a by value to function. As C has only value-semantics, it can only copy values in this case. So, you initialise the parameter (even if your implementation doesn't care about the parameter) with an unitialised object, wich requires reading from that object. This is undefined behaviour, hence the compiler informs you that you are doing something illegal.
If you pass the object via a pointer, you still pass-by-value, but the value being copied is the pointer. Hence you don't have to read the actual value and your compiler wont complain.
Observe:
void flat(student s) {
s.age = 20;
}
void ptr(student* s) {
s->age = 20;
}
int main() {
student s = {"Eve", 0};
// { s.age == 0 }
flat(s);
// { s.age == 0 } --- still the same, no change
ptr(&s);
// { s.age == 20 } --- now it has changed
}
I am working on an assignment and ran into challenging problem. As far as I'm concerned and from what I've learnt the code that follows should be correct however it does not work. Basically what I am trying to is copy a string value into the variable member of a structure the is part of an array passed into a method as a pointer. What am I missing?
typedef struct
{
char * name; //variable in struct I am trying to access
} Struct;
void foo(Struct * arr) //array of Structs passed into function as a pointer
{
int i = 0;
while(i++ < 2)
{
arr[i].name = malloc(sizeof(char *)); //assigning memory to variable in each Struct
arr[i].name = strdup("name"); //copying "name" to variable in each Struct
printf("C - %s\n", arr[i].name); //printing out name variable in each Struct
}
}
main()
{
Struct * arr; //defining pointer
arr = calloc(2, sizeof(Struct)); //allocating memory so pointer can hold 2 Structs
foo(arr); //calling function foo passing pointer into function
return 0;
}
This code compiles and runs however it does not do what it is designed to do. Forgive me if it is something trivial. I am new to the language C
Two issues:
while(i++ < 2) This line changes the value of i as soon as it checks it, so your loop body will not be the same as it was checked.
arr[i].name = strdup("name"); overwrites the value of the .name pointer, causing a memory leak of the memory you malloc()'ed earlier.
Extending on 2 pointed out correctly already,
arr[i].name = strdup("name");
Even if you use following instead of above,
strcpy(array[i].name, "name");
you haven't allocated enough bytes to store the string i.e. this is wrong
arr[i].name = malloc(sizeof(char *));
// even if pointer is 8 byte here, concept isn't right
Should be something like
arr[i].name = malloc(strlen("name")+1);
// or MAX_SIZE where it is greater than the possible "name".
Or better yet, remove the malloc at all, strdup takes care of allocation itself
This is not answering your question directly, but addresses an issue to big to put into a comment...
Additional issue: You probably did not intend to allocate only a (char *) worth of memory to a variable intended to hold at least "name". Change;
arr[i].name = malloc(sizeof(char *));
to:
arr[i].name = malloc(sizeof(char)*strlen("name")+1); //+1 for '\0'
or better yet, use char *name="name";, then:
arr[i].name = malloc(sizeof(char)*strlen(name)+1);
Even more general (and better):
char *name;
name = malloc(strlen(someInputString)+1);
//do stuff with name...
free(name);
Now, you can allocate name to any length needed based on the length of someInputString.
[EDIT]
Etienz, I wanted to address one more thing, alluded to by #H2CO3 above, but not really explained, that I think might be useful to you:
Regarding your desire to have room for two structs, because you typedef'd your struct, you can simply do something like this: (but I am going to change the name you used from Struct to NAME :) The whole point being that when a struct is created as an array, you do not need to use calloc or malloc to create space for them, it is done as shown below...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *name;
}NAME;
//use new variable type NAME to create global variables:
NAME n[2], *pN; //2 copies AND pointer created here
//prototype func
int func(NAME *a);
int main()
{
pN = &n[0]; //pointer initialized here
func(pN); //pointer used here (no malloc or calloc)
printf("name1 is %s\nname 2 is %s", pN[0].name, pN[1].name);
return 0;
}
int func(NAME *a)
{
char namme1[]="andrew";
char namme2[]="billebong";
//You DO have to allocate the members though
a[0].name = malloc(strlen(namme1)+1);
a[1].name = malloc(strlen(namme2)+1);
strcpy(a[0].name, namme1);
strcpy(a[1].name, namme2);
return 0;
}
for instance this code:
struct test{
int ID;
bool start;
};
struct test * sTest;
void changePointer(struct test * t)
{
t->ID = 3;
t->start = false;
}
int main(void)
{
sTest->ID = 5;
sTest->start = true;
changePointer(sTest);
return 0;
}
If I was to execute this code, then what would the output be? (i.e. if I pass a pointer like this, does it change the reference or is it just a copy?)
Thanks in advance!
Your program doesn't have any output, so there would be none.
It also never initializes the sTest pointer to point at some valid memory, so the results are totally undefined. This program invokes undefined behavior, and should/might/could crash when run.
IF the pointer had been initialized to point at a valid object of type struct test, the fields of that structure would have been changed so that at the end of main(), ID would be 3. The changes done inside changePointer() are done on the same memory as the changes done in main().
An easy fix would be:
int main(void)
{
struct test aTest;
sTest = &aTest; /* Notice the ampersand! */
sTest->start = true;
changePointer(sTest);
return 0;
}
Also note that C before C99 doesn't have a true keyword.
The only question is why do you need a test pointer in a global name space? Second is that you do not have any memory allocation operations. And you have a pointer as an input parameter of your function. Therefore structure where it points to will be changed in "changePointer".
1) First thing your code will crash since you are not allocating memory for saving structure.. you might need to add
sText = malloc(sizeof(struct test));
2) After correcting the crash, you can pass structure pointer and the changes you make in changePointer function will reflect in main and vizeversa..
3) But since you are not printing anything, there wont be any output to your program..
typedef struct Model
{
int recordId;
char *name;
}Model;
typedef struct ModelArray
{
//keeps the size that the array was initially create with. When more elements are needed
//we use this to add that many more elements
int originalSize;
//total number of elements that can be used
int elements;
//total number of elements used
int count;
//the actual array is stored here
Model *source;
}ModelArray;
void initModelArray(ModelArray *array, int numberOfElements)
{
array->originalSize = numberOfElements;
array->elements = numberOfElements;
array->count = 0;
array->source = malloc(sizeof(Model)*numberOfElements);//0 bytes in 3 blocks are definitely lost in loss record 1 of 65
}
void deallocModelArray(ModelArray *array)
{
if(array == NULL)
return;
array->elements = 0;
array->count = 0;
free(array->source);
array->source = NULL;
free(array);
}
main(int argc, const char * argv[])
{
ModelArray *models = malloc(sizeof(ModelArray));
initModelArray(models, 10);
deallocModelArray(models);
}
What is lost? Code looks fine to me. I'm sure I could say array->source = NULL first but it's not needed, right?
To deallocate these structures correctly, you need to do the following, in this order:
free(models->source);
free(models);
If you do anything else, you're leaking memory.
Edit:
OK, having seen the Model struct, you're probably leaking the names, or at least valgrind thinks you do because you deallocate the ModelArray structure, which contains a pointer to a Model structure, which contains a char* which you don't free first.
So:
int i;
for( i=0; i<models->originalSize; i++ ) {
if( models->source[i]->name != NULL ) {
free( models->source[i]->name );
}
}
free(models->source);
free(models);
And it would be a good idea to use calloc() instead of malloc() when allocating models->source in the first place. This will set all the name pointers to 0. Without this, the test for models->source[i]->name being non-NULL above might fail if name happens to contain some garbage (since using uninitialized memory produces undefined behavior.)
Er... Yes, the memory is lost. Of course, it is lost, since you "left out dealloc code"!
How could you possibly expect anyone to answer your question when you "left out dealloc code"? The very essence of your question is whether your dealloc code is correct or not. And you decided to leave it out?
On top of that, there quite a few thing that make little sense in your code. What is
typedef struct ModelArray {
...
Model *source;
...
} Model;
supposed to mean? Why are you typedefing struct ModelArray as Model? In fact, your code will not even compile, since Model * is used inside the struct, where it is not declared yet. You also use ModelArray type in your code, while in reality there's no such type. You have struct ModelArray, but not just ModelArray. The code you posted is not real code. Post real code, please. (Apparently it was supposed to be typedef struct ModelArray { ... } ModelArray; with Model defined elsewhere.)
Finally, as an unrelated note, // comments is a C99 feature. In C99 the function return type cannot be omitted (no "implicit int" rule in C99), meaning that you have to declare your main function as int main.