My program crashes when I set a pointer to a NULL - c

this is driving me nuts, I've done my homework but for some reason here
for (int i = 0; i < room->num_of_challenges; i++) { // need a check
if (strcmp(room_to_enter, room->challenges[i].challenge->name) == 0) {
room->challenges[i].start_time = start_time;
room->challenges[i].visitor = malloc(sizeof(room->challenges[i].visitor));
room->challenges[i].visitor->current_challenge = malloc(sizeof(room->challenges[i].visitor->current_challenge));
*room->challenges[i].visitor->current_challenge = room->challenges[i];
*room->challenges[i].visitor->room_name = NULL;
*room->challenges[i].visitor->room_name = malloc(strlen(room_to_enter)+1);
strcpy(*room->challenges[i].visitor->room_name, room_to_enter);
inc_num_visits(room->challenges[i].challenge);
}
}
the program just crashes for some reason, at this point:
*room->challenges[i].visitor->room_name = malloc(strlen(room_to_enter)+1);
it's a 3 pages code with headers for each, and each page is about 300 line, so I can't post them all, also here are the structs:
struct SChallengeActivity;
typedef struct SVisitor
{
char *visitor_name;
int visitor_id;
char **room_name;
struct SChallengeActivity *current_challenge;
} Visitor;
typedef struct SChallengeActivity
{
Challenge *challenge;
Visitor *visitor;
int start_time;
} ChallengeActivity;
typedef struct SChallengeRoom
{
char *name;
int num_of_challenges;
ChallengeActivity *challenges;
} ChallengeRoom;
We can't edit the struct because it's given by the homework like that, the thing is I tried to set this line to NULL, like so:
*room->challenges[i].visitor->room_name = NULL;
and it still crashes at that line too, for some reason it can't reach that field in the struct.
Note: ignore the coding, I know I should check the malloc after each line, but for now I want it to work, I've been up all night to get it to work, and I couldn't, any help please ?
Thank you

When allocating memory for the visitor, you are only allocating the aize of a pointer. The visitor field inside your challenge is only a pointer to a Visitor. Thus you are not allocating enough memory. You should use:
malloc(sizeof(Visitor))
To get the real size of the Visitor structure and allocate ample space.
Also, setting pointers to null before allocating is useless. The call to malloc() will overwrite them.

Also,
*room->challenges[i].visitor->room_name = NULL;
room_name is a char** (pointer-to-pointer), which means it's still a pointer, and you dereference it before it's set.
Not sure why it needs to be a pointer-to-pointer, but if it needs to be, then you first have to allocate memory for one or more pointers (eg array):
room->challenges[i].visitor->room_name = malloc(sizeof(char*)*1);
*room->challenges[i].visitor->room_name = malloc(strlen(room_to_enter)+1);
...

Related

Program Crashes When Accessing array inside Struct

I'm trying to implement the first part of an autocomplete feature that takes in a string, calculates an index for a particular letter, and then allocates another struct pointer at that index. It also stores possible completions of words in a string array. For some reason, the program crashes when I try to access the string array field, and I can't figure out why. How can I fix this?
Thanks
struct table {
struct table *next[26];
char **complete;
int lastIndex;
int size;
};
static struct table Base={{NULL},NULL,0,0};
void insert(const char *string){
int index=string[0]-'a';
if(Base.next[index]==NULL){
Base.next[index]=(struct table*)malloc(sizeof(struct table));
*Base.next[index]=(struct table){{NULL},NULL,0,0};
}
struct table *pointer=Base.next[index];
if(pointer->lastIndex==pointer->size){ //expand complete array
pointer->complete[pointer->lastIndex] = strdup(string); //program crashes here
pointer->lastIndex=pointer->lastIndex+1;
}
}
The crash in this line
pointer->complete[pointer->lastIndex] = strdup(string);
is because pointer->complete is NULL. In other words, you forgot to allocate memory for complete.
How can I fix this?
You must allocate memory. It seems that you want a dynamic sized array of char pointers. So you'll need to use realloc so that you both extend the allocated memory and preserve previous values.
Something like:
char** tmp = realloc(pointer->complete, (pointer->lastIndex + 1) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
// Then you can do your normal code
pointer->complete[pointer->lastIndex] = strdup(string);
Notice: Though it's possible to use realloc every time you insert a string, it may perform rather bad.
So instead of reallocating memory for every new string, it may be better to reallocate a chunk of memory each time you call realloc. Like:
if (pointer->lastIndex == pointer->size)
{
// Need more memory
// - if it's the first time just start with 10 (or another number)
// - else double the size
pointer->size = (pointer->size != 0) ? 2 * pointer->size : 10;
char** tmp = realloc(pointer->complete, (pointer->size) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
}
Here I decided to double the allocated memory when doing realloc. You can of cause use ant approach you like instead, e.g. always add 10 more instead of doubling.
BTW: The name lastIndex seems poor as it's really a nextIndex variable.
A final word on data structure
Your data structur, i.e. struct table seems a bit strange to me. At base-level, you only use table. At the next level you don't use table but only the other variables.
Seems to me that you should split up the struct into two structs like:
struct StringTable {
char **complete;
int lastIndex;
int size;
};
struct table {
struct StringTable strings[26];
};
That would save you both memory and some of the dynamic memory allocation.
You are assuming that
const char * string
will contain only small case alphabets. Dictionaries also have apostrophes
add that case.

C: How to free a struct ** that contains fields which are char* and ENUM (int)?

My code contains the struct BeforeTriag which is from type Patient** .
here is the structs and it's fields:
typedef struct{
char Id[ID_SIZE];
char Name[NAME_SIZE];
char LastName[NAME_SIZE];
char PhoneNum[PHONE_SIZE];
STATUS Status;
char Address[ADDRESS_SIZE];
}Patient;
Here is my initilization and allocation:
Patient** BeforeTriag = NULL;
int* BeforeTriagSize[1] = { 0 };
BeforeTriag = (Patient**)malloc(sizeof(Patient*));
if (!(BeforeTriag))
{
printf("ERROR!Out of memory!");
exit(1);
}
*BeforeTriag = (Patient*)malloc((PatientArraySize)* sizeof(Patient));
if (!(*BeforeTriag)){
printf("ERROR!Out of memory!");
exit(1);
}
here i'm tring to free each field in the struct:
for (i = 0; i < (*BeforeTriagSize); i++){
free((BeforeTriag)[i]->Id);
free((BeforeTriag)[i]->Name);
free((BeforeTriag)[i]->LastName);
free((BeforeTriag)[i]->Address);
free((BeforeTriag)[i]->PhoneNum);
}
free(BeforeTriag);
When I am debugging it crush on the first row of the free id:
free((BeforeTriag)[i]->Id);
What should i do to free as proper?
The individual fields within BeforeTriag[i] were not dynamically allocated by themselves, so you can't free them. You need to free the struct as a whole, because that's what was allocated:
for (i = 0; i < (*BeforeTriagSize); i++){
free(BeforeTriag[i]);
}
free(BeforeTriag);
You do not have to do this:
for (i = 0; i < (*BeforeTriagSize); i++){
free((BeforeTriag)[i]->Id);
free((BeforeTriag)[i]->Name);
free((BeforeTriag)[i]->LastName);
free((BeforeTriag)[i]->Address);
free((BeforeTriag)[i]->PhoneNum);
}
Because they are not dynamically allocated.
But you have to free BeforeTriag[i] inside the loop.
for (i = 0; i < (*BeforeTriagSize); i++){
free(BeforeTriag[i]);
}
free(BeforeTriag);
While #dbush and #RolBrok already pointed out correctly that there's no need to free the individual members, there is another bug in your code:
int* BeforeTriagSize[1] = { 0 };
This line initalizes a int ** to zero. I'm not really sure why you want this variable to be in an array, but anyway, the correct way to declare it would be
int BeforeTriagSize[1] = { 0 };
(If you only need one value for BeforeTriagSize anyway, just declare it as an int!)
Edit:
Another thing you should look closer into is the way you're allocating memory for your structs:
*BeforeTriag = (Patient*)malloc((PatientArraySize)* sizeof(Patient));
With this you're always writing to the same pointer. So when you are allocating the memory for the second struct, you are overwriting the position of the first one, basically causing a memory leak.
Consider something along the line of
BeforeTriag[BeforeTriagSize++] = (Patient*)malloc((PatientArraySize)* sizeof(Patient));
This ensures that you are writing to a new position in your array every time. (Assuming you changed BeforeTriagSize to an int - if you need to hand it over as a pointer to some functions just use the address operator (&))

Realloc Causes Heap Corruption

I am trying to write a code in C where I am facing an issue with the realloc. The code works fine at some point of time, but crashes with a Heap Corruption error during the realloc at another time.
I have pasted the structures and the function that populates the data into it. Could anyone please tell me if I am doing something wrong here.
typedef struct MyDataStructureStr
{
MyDataStructureStr()
{
val1 = -1;
val2 = -1;
}
int val1;
int val2;
} MyDataStructureStr, *MyDataStructurePtr;
typedef struct MyStructureStr
{
MyStructureStr()
{
connector = NULL;
counter = 0;
}
MyDataStructurePtr connector;
int counter;
}MyStructureStr, *MyStructurePtr;
static void storeData(int first, int second)
{
if(myStruct->connector == 0)
myStruct->connector = (MyDataStructurePtr)malloc(sizeof(MyDataStructureStr);
else
myStruct->connector = (MyDataStructurePtr)realloc(myStruct->connector, sizeof(MyDataStructureStr) * (myStruct->counter + 1));
myStruct->connector[myStruct->counter].val1 = first;
myStruct->connector[myStruct->counter].val2 = second;
myStruct->counter++;
}
Any suggestions are welcome.
Thanks in advance
A few points.
You do not need do the if(myStruct->connector == 0) thing. realloc will allocate memory if passed a NULL pointer. Per the man page: If ptr is NULL, then the call is equivalent to malloc(size), for all values of size'.
Your typedef struct functions are legal, but you should note they aren't being called.
I can't see where counter is being initialized to zero or connector to NULL. This may be because you haven't pasted the whole program.
I think the actual problem is that you are allocating counter data structures of sizeof(MyStructureStr). This should be sizeof(MyDataStructureStr) if I understand what you are doing. This may be the cause of the heap corruption but without a full program it's hard to tell.
Something else in the program (that you haven't pasted) may be corrupting the heap.
valgrind is the best way to debug this sort of problem

List to list assignment becomes garbage

I'm having some trouble with the following:
void BuildList(cs460hwp hw)
{
FILE* fp;
fp = fopen("HW2input.dat", "r");
if(fp == NULL)
{
printf("Couldn't open the file.");
return;
}
int numStudents;
int i;
bool success;
char* dueDate = malloc(9*sizeof(char));
char* course = malloc(7*sizeof(char));
char* wsuid = malloc(9*sizeof(char));
char* subDate = malloc(9*sizeof(char));
double points1 = 0;
double points2 = 0;
cs460hwp stuInsert = NULL;
fscanf(fp, "%d", &numStudents);
fscanf(fp, "%s", dueDate);
for(i = 0; i < numStudents; i++)
{
stuInsert = malloc(sizeof(cs460hwp));
fscanf(fp, "%s %s %s %lf", course, wsuid, subDate, &points1);
strcpy(stuInsert->course, course);
strcpy(stuInsert->wsuid, wsuid);
strcpy(stuInsert->subdate, subDate);
stuInsert->points1 = points1;
stuInsert->points2 = CalculatePoints(dueDate, subDate, points1);
stuInsert->nextPtr = NULL;
if(hw == NULL)
{
hw = stuInsert;
}
else
{
stuInsert->nextPtr = hw;
hw = stuInsert;
}
}
free(course);
free(wsuid);
free(subDate);
free(dueDate);
PrintGrades(hw);
fclose(fp);
}
struct hwpoints
{
char course[7];
char wsuid[9];
char subdate[9];
double points1;
double points2;
struct hwpoints *nextPtr;
};
typedef struct hwpoints *cs460hwp;
My goal here is to insert every entry to the top of the list. However, whenever I try to assign anything to nextPtr (such as in the else clause), it gets filled with garbage values. They're mostly truncated versions of old data, which leads me to believe they're being taken from the heap. I've been reading (a lot), but I'm having trouble finding advice on this particular problem.
nextPtr always becomes junk, and nextPtr->nextPtr causes a segfault. For every iteration of the loop. hw remains fine, but its pointer value never gets updated properly.
Even when I've attempted to move the memory allocation for the struct into a function, I've had the same (or similar) issues.
Can anyone point me in the right direction?
Two problems.
1) As pb2q mentioned, you are passing a pointer to a struct and trying to assign what the arg points to. That's allowed by the compiler, but it doesn't do anything for you outside the function. It might be OK in your case if:
void main()
{
cs460hwp hw = NULL;
BuildList(hw);
return;
}
Is the whole of your function. I don't know the assignment so you need to figure out if that's acceptable to you or not.
2) The much bigger problem:
stuInsert = malloc(sizeof(cs460hwp));
Did you check what sizeof(cs460hwp) comes out to be? it's 4. You're allocating enough memory for the size of a pointer, not the size of your structure. I'm pretty sure this is not what you want to do and this is what is killing you. Just for kicks, replace it with malloc(100) and see if your problem goes away. If so you just need to figure out what size you really want. ;)
A problem with your BuildList function is that you're passing a pointer to a struct hwpoints, and you're trying to re-assign what the argument points to. Since function arguments in C are pass-by-value you're only changing the copy of the pointer that your function receives, and those changes won't be reflected in the caller.
You can use this pointer to modify the contents of the list: you can change e.g. hw->course or hw->nextPtr, you can move elements around in your list. But you can't change what the head, hw points to, so you can't insert elements at the beginning of the list.
If you want to change your head pointer, as in these statements:
hw = stuInsert;
// ...
hw = stuInsert;
Then you'll need to pass a pointer to the pointer:
void BuildList(cs460hwp *hw)
And de-reference it as necessary in the body of the function.
I can't be sure that this is the cause of the output that you're observing, which may be due to other problems. But if, after some number of calls to BuildList, beginning with a head pointer equal to NULL, you're trying to print your list assuming that it has valid nodes, you could see garbage data.
Thanks to #Mike's answer, we see also that you're not allocating enough space for your list nodes:
stuInsert = malloc(sizeof(cs460hwp));
Will only allocate enough space for a pointer, since cs460hwp is typedef'd to be a pointer to struct hwpoints. You need to allocate enough space for the structure, not a pointer to it:
stuInsert = malloc(sizeof(struct hwpoints));

Is valgrind right? Is the memory lost?

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.

Resources