studying C for few months, I encounter some difficulties with the use of pointers when dynamically building a binary tree:
Given my code below:
typedef struct TNoeud
{
int data;
struct TNoeud *pFilsGauche;
struct TNoeud *pFilsDroit;
} TNoeud;
void insereData(int data, TNoeud **pRacine)
{
TNoeud *noeud=malloc(sizeof(TNoeud));
noeud->data=data;
noeud->pFilsDroit=NULL;
noeud->pFilsGauche=NULL;
while((*pRacine)!=NULL)
{
if(data<(*pRacine)->data)
{
pRacine=&(**pRacine).pFilsGauche;
}
else
{
pRacine=&(**pRacine).pFilsDroit;
}
}
if(pRacine==NULL)
{
*pRacine=noeud;
}
free(noeud);
}
And in the main:
int main(int argc, const char * argv[]) {
TNoeud *pRacine=malloc(sizeof(TNoeud));
pRacine->data=0;
pRacine->pFilsGauche=NULL;
pRacine->pFilsDroit=NULL;
pRacine=&noeudRacine;
insereData(4, &pRacine);
return 0;
}
I read the following topic https://stackoverflow.com/a/28637104/7866010 for the BAD_ACCESS, but in my case, the pointer is not at NULL, as pRacine is assigned at 0.
I read the following topic https://stackoverflow.com/a/15154553/7866010 , but it didn't help.
I also tried the declaration variant
(*pRacine)->data
found in this topic https://stackoverflow.com/a/346739/7866010 without any difference.
So my questions are :
[SOLVED with TNoeud noeud as pointer instead of local variable. I also changed pRacine in the main the same way] Why do the pointer
*pRacine == NULL
when I pass a pointer to an assigned value as parameter of
insereData(4, &pRacine) ?
[SOLVED the same way] Why does the debugger give me random values to pointers
[1] = 0x00007fff5fbff700)
and datas
(int) data = 1606416544)
I didn't willingly assigned ?
[SOLVED: by deleting the if(pRacine==NULL) condition and replacing it by just (*pRacine)=noeud;] Now no more errors, but the result of
insereData(4, &pRacine);
doesn't impact pRacine : it should be
pRacine->pFilsDroit->data==4
but here it remains at NULL. I don't understand why, as it's not a local variable anymore.
Thanks all for your answers!
Some suggestions(not law).
First in order to not confuse yourself about pointers, just work with them as arrays. it really works and won't confuse you.
For instance given pointer int* ptr, for accessing the first element go as ptr[0].
And the problem is here
if(pRacine==NULL)
{
*pRacine=&noeud;
}
as the noeud is not in dynamic memory, it gets halted.
You simply need to define the noeud as a pointer of the struct by malloc. But for memory sake, please keep an eye for free it once it's not needed.
Related
I need to make a program for bakery managment, I've done structures and three pointer arrays that must contain pointers for object of these structures. But i can't make function to add new bakery because it needs dynamic memory allocating. I've tried to do this but it throws Segmentation Fault on realloc. I would be grateful for any advice how to properly reallocate memory for these arrays to add element. Also feel free to make comments about other errors in the code, I'm just learning.
typedef struct BakeryType {
char *name;
} BakeType;
typedef struct Bakerys {
char *name;
BakeType *type;
char *photo;
float weight;
int portions;
float price;
char *description;
} Bakery;
Bakery *bakeryList[0];
BakeType *bakeTypeList[0];
void addBakery() {
Bakery new;
*bakeryList = realloc(*bakeryList, (sizeof(bakeryList)/ sizeof(Bakery))+ 1);//Segmentation Fault
bakeryList[sizeof(bakeryList)/sizeof(Bakery)]=&new;
}
bakeryList is a zero-element array of pointers to Bakery. It has room for zero pointers.
Yet later you set the first element of this array (*bakeryList which is the same as bakeryList[0]) to whatever comes back from realloc. So you're overwriting something, and it probably goes downhill from there.
I think you want bakeryList to just be a pointer to Bakery. That's how dynamically-allocated arrays work in C: you define a pointer to the first element and use pointer math (e.g., bakeryList[5] or *(bakeryList + 5)) to access other elements.
Another issue is your use of sizeof(bakeryList). sizeof is an operator that's evaluated by the compiler. It doesn't change at runtime. sizeof(bakeryList) / sizeof(Bakery) will evaluate to zero because you defined bakeryList as a zero-element array. You need another variable to keep track of how many elements are actually in the array at runtime.
Something like this would work:
int bakeryCount = 0;
Bakery *bakeryList = NULL;
void addBakery() {
// Add one to the array.
bakeryCount++;
bakeryList = realloc(bakeryList, bakeryCount * sizeof (Bakery));
// Create a pointer to the new element at the end of the array.
Bakery *newBakery = bakeryList + bakeryCount - 1;
// Set all the fields. Note that they will probably contain
// garbage so you should set them all.
newBakery->name = ...
}
I have to set a reference pointed by a pointer to NULL.
But the function deleteP(...) doesn't seem to work, indicated by the Output.
The functions delete() and memoryset() work in some way, even if the latter just fills the memory (pointed to by the pointer in the array) with zeroes.
I want the pointer in the array to finally be NULL and that is not working.
I need to do everything (i.e. set fs->child[20] to NULL etc.) via pointer to the struct (which is elin my code, a local pointer variable inside deleteP(...) ). This is because I am iterating over fs children, and their children after that, a lot of times, and I put the current child in el.
How could I solve it?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define HEIGHT 255
#define LENGTH 256
#define MAX_CHILDREN 1024
typedef struct FS FS;
typedef struct Elem Elem;
struct Elem {
char name[LENGTH];
char content[256];
int isFile;
int emptyCells;
Elem *child[MAX_CHILDREN];
};
struct FS {
int emptyCells;
Elem *child[MAX_CHILDREN];
};
void delete(FS *fs){
free(fs->child[20]);
fs->child[20] = NULL;
}
void deleteP(FS *fs){
Elem *el = calloc(1, sizeof (Elem));
el = fs->child[20];
free(el);
el = NULL;
}
void memoryset(FS *fs){
Elem *el = calloc(1, sizeof (Elem));
el = fs->child[20];
memset(el, 0, sizeof(Elem));
}
int main(int argc, const char * argv[]) {
FS *fs = calloc (1, sizeof(FS));
fs->emptyCells = MAX_CHILDREN;
fs->child[20] = calloc (1, sizeof(Elem));
strcpy(fs->child[20]->name, "Hello");
printf("No delete: %s\n", fs->child[20]->name);
memoryset(fs);
printf("MEMSET: %s\n", fs->child[20]->name);
fs->child[20] = calloc (1, sizeof(Elem));
strcpy(fs->child[20]->name, "Hello");
delete(fs);
printf("Delete: %s\n", fs->child[20]->name);
fs->child[20] = calloc (1, sizeof(Elem));
strcpy(fs->child[20]->name, "Hello");
deleteP(fs);
printf("DeleteP: %s\n", fs->child[20]->name);
}
Output:
No delete: Hello
MEMSET:
Delete: (null)
DeleteP: Hello
Allow me to phrase your goal in my words
(after verifying my understanding in chat):
you want to free memory pointed to by a pointer which is stored in an array,
which is inside a struct, which you get a pointer to
you cannot access the array member directly,
only via the pointer to the containing struct
you also want to write NULL to the array member
looking at your code, you attempted to do that by making a copy of the array member (which is a pointer)
it mostly works, only that the array member does not end up being NULL
(and some problems mentioned by xing and BLUEPIXY)
Basically, you need a pointer to the array member, instead of a copy of the array member.
So your function should be:
void deleteP(FS *fs){
Elem **el; // pointer to pointer, instead of pointer (and no calloc)
el = &(fs->child[20]); // pointer to array member
free(*el); // free the pointer in the array member (not a copy of it),
// though the effect is the same
*el = NULL; // write NULL to the array member, not a copy of it,
// this is what changes the effect to what you want
}
If I did not mistype anything, this is more or less the result of our chat.
And as far as I understand, it solves your problem. Cheers.
As far as I can tell, this should also fix the memory leak found by xing inside deleteP(...).
But be careful to also fix it in memoryset(...).
This does NOT fix the problems of UB (undefined behaviour) as found by BLUEPIXY.
For this you need to rework your debug prints and make sure not to dereference any pointers to already freed memory (question of order of doing things) and also not to dereference any pointer which was set to NULL.
By the way, this could be done without a local pointer variable; doing everything via the parameter fs. But I kept the solution closer to your own code for better clarity of what is the difference. Also in my opinion your way of doing it via local pointer is more readable. It might even be faster, but seeing how good modern compilers are, I doubt it; the actual reason is clarity and readability.
What i´m trying to do is assigning strings to pointers in a vector from a separate function for that use. unfortunately i keep getting either a lot of warnings or errors or bus trap:10.
here´s the code so far here i commented where i´m having issues:
#include <stdio.h>
#include <stdlib.h>
void read_top(FILE **read,short int *L, short int *D, short int *N){
fscanf(*read,"%hd %hd %hd",L,D,N); // L being the size of the strings, D being how many strings there are and N doesn´t matter for this question
fgetc(*read); // remove \n
}
void save_words(FILE **read,char **dic,short int L,short int D){ // i´m having problems here assigning strings to the pointers
int e;
for (e = 0;e < D;e++){
*dic[e] = malloc(125);
fgets(*dic[e],L+1,*read);
fgetc(*read);
}
}
void open(FILE **read,FILE **write) {
*read = fopen("teste4.in","r");
*write = fopen("Allien_language","w");
}
void alloc(char **dic,D,L){ //i´m having problems here allocating memory for each pointer to point to
int e;
for (e = 0;e < D; e++){
*dic[e] = malloc(L);
}
}
main(){
FILE *read,*write;
open(&read,&write);
short int L,D,N;
read_top(&read,&L,&D,&N);
char *dic[D]; // here´s the array of pointers
alloc(dic,D,L); // here´s the funtion i can´t get to work
save_words(&read,dic,L,D); // here´s the function that i can´t get to work
//printf("\n%s\n",dic[0]);
}
I´ve tried multiple things, but i think the main problem is not knowing exactly how things work. this includes passing the array to the function and assigning the strings to it and allocating the memory for each pointer. I´ve also been searching in this site for my questions, where i found solutions to similar problems but didn´t understand exactly their solutions. If someone could explain me exactly how things should work i would appreciate that.
thanks in advance
When you do e.g. *dic[e] = malloc(...) you're doing it wrong. What the expression *dic[e] does is get element e of the array dic, which is a pointer to char, then you dereference the pointer giving you the value of what dic[e] is pointing to. Unfortunately dic[e] doesn't point anywhere yet, which would lead to undefined behavior and a probable crash if the compiler didn't give you an error.
And you get an error because you try to assign the pointer returned by malloc to something that's not a pointer.
So the solution? Remove the dereference, and just do e.g. dic[e] = malloc(...).
You have the same problem when you try to read the string from the file in save_words. And there you have another problem, you allocate memory for the string again, making you loose the original allocation from the alloc function, and leading to a memory leak.
The problem is that you are treating elements of the array of pointers incorrectly: rather than assigning
*dic[e] = malloc(L);
you should be assigning
dic[e] = malloc(L);
without the dereference operator.
The reason for this is that you are passing an array of uninitialized pointers, so you may not dereference them. However, you can certainly assign them, which is what dic[e] = malloc(L) does.
You have the same problem in save_words. The fix is even simpler there - you need to drop the *dic[e] = malloc(125); line, because it re-assigns a pointer that has been assigned already.
Finally, you need to remove dereference operator from this line as well:
fgets(dic[e],L+1,*read); // No asterisk in front of "dic[e]"
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.