munmap_chunk(): invalid pointer while freeing a struct in an array - arrays

So I wrote a program where I have to realloc an array of structs whenever I want to add something to it.
But when I try to free the array, I free every element individually but I get a munmap_chunk(): invalid pointer at some point.
Here is the full code :
#include <stdlib.h>
#include <string.h>
struct Date {
int day;
int month;
int year;
};
struct Person {
char *name;
char *surname;
struct Date birth;
};
struct Directory {
int size;
struct Person *array;
};
struct Date create_date() {
struct Date date = {
.day = 0,
.month = 0,
.year = 0
};
return date;
}
struct Directory create_directory() {
struct Directory directory = {
.size = 0,
.array = NULL
};
return directory;
}
struct Person *create_person() {
struct Person *person_ptr = (struct Person *) malloc(sizeof(struct Person));
person_ptr->name = NULL;
person_ptr->surname = NULL;
return person_ptr;
}
void copy_date(struct Date *dest, struct Date *src) {
dest->day = src->day;
dest->month = src->month;
dest->year = src->year;
}
void initialize_person(struct Person *person_ptr, char *name, char *surname, struct Date *birth) {
if (name != NULL && surname != NULL && birth != NULL) {
person_ptr->name = realloc((*person_ptr).name, (strlen(name) * sizeof(char)) + 1);
strcpy(person_ptr->name, name);
person_ptr->surname = realloc((*person_ptr).surname, (strlen(surname) * sizeof(char)) + 1);
strcpy(person_ptr->surname, surname);
copy_date(&person_ptr->birth, birth);
}
}
void copy_person(struct Person *dest, struct Person *src) {
dest->name = realloc((*dest).name, (strlen(src->name) * sizeof(char)) + 1);
dest->surname = realloc((*dest).surname, (strlen(src->surname) * sizeof(char)) + 1);
struct Date date = create_date();
dest->birth = date;
strcpy(dest->name, src->name);
strcpy(dest->surname, src->surname);
copy_date(&dest->birth, &src->birth);
}
int add_person(struct Directory *directory_ptr, const struct Person *new_person_ptr) {
int return_code = 0;
directory_ptr->size++;
directory_ptr->array = realloc(directory_ptr->array, (directory_ptr->size * sizeof(struct Person)));
if (directory_ptr->array) {
copy_person(&directory_ptr->array[directory_ptr->size - 1], (struct Person *) new_person_ptr);
} else {
return_code = 1;
}
return return_code;
}
int add_multiple_persons(struct Directory *directory_ptr, const struct Person **persons_ptr, int nb_persons) {
for (int i = 0; i < nb_persons; i++) {
add_person(directory_ptr, (persons_ptr[i]));
}
return 0;
}
void destroy_person(struct Person *person_ptr) {
free(person_ptr->name);
person_ptr->name = NULL;
free(person_ptr->surname);
person_ptr->surname = NULL;
free(person_ptr);
person_ptr = NULL;
}
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
for (int i = 0; i < directory_ptr->size; i++) {
destroy_person(&directory_ptr->array[i]);
}
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
int main(void) {
struct Directory directory = create_directory();
struct Person *person1 = create_person();
struct Person *person2 = create_person();
struct Person *person3 = create_person();
struct Date date = {
.day = 17,
.month = 04,
.year = 1999};
initialize_person(person1, "Marcel", "Juan", &date);
initialize_person(person2, "Albin", "Michel", &date);
initialize_person(person3, "Suzerain", "Bernard", &date);
const struct Person *array[] = {
person1,
person2,
person3
};
add_multiple_persons(&directory, array, 3);
destroy_person(person1);
destroy_person(person2);
destroy_person(person3);
destroy_directory(&directory);
return 0;
}
I've been on this error for more than a week, and it keeps bugging me.
How can I fix this ?

In the destroy_directory function, you freed the persons contained by the array. But in this array you didn't put pointers to structures but the structures themselves. Therefore you must free the space you allocated for the array and nothing else :
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
free(directory_ptr->array); //<==== Here
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}

person_ptr is a part of the memory allocated at directory_ptr->array. You need to remove this line.
As a rule of gold, memory responsible is the same while allocation and while freeing. In your code, the person holder is the array inside directory_ptr, which is allocated by add_person. Despite its name, it is a directory manager, so freeing its memory should be done only on directory destroyer.

Related

Pointers to a struct inside a struct

I have two structures (one_d and two_d).
I have a function that will take struct two_d *smg as input. In main(), I am trying to create such smg so it will return value c increased.
My problem is that, while creating an array of struct two_d smg[2], I am not sure how to put inside information about its values, as it is a pointer to a different struct.
So how do you use pointer to a struct inside a struct? I would like to create struct two_d smg[2] but i dont now how to deal with struct one_d *a field in it
#include <stdio.h>
enum sid
{
DRB,
DRA,
};
struct one_d
{
unsigned int r;
unsigned int *p;
};
struct two_d
{
struct one_d *a;
enum sid z;
};
unsigned int getSmg(struct two_d *smg)
{
unsigned int c = 0;
const struct two_d *sd = NULL;
const struct one_d *ed = NULL;
for (sd = smg; sd->a != NULL; ++sd)
{
for (ed = sd->a; ed->p != NULL; ++ed)
{
if (DRA == sd->z)
{
/*P Increment the clear-state buffer size */
c += 1 + ed->r;
}
}
}
return c;
}
int main(void)
{
unsigned int rVal = 0;
struct two_d smg[2]={
//
// [0].a ={1,0},
// [0].z =DRA,
// [1].a={1,0},
// [1].z =DRA,
};
rVal = getSmg(smg);
printf("Return value is a %d\n", rVal);
printf("Return value is a l");
return( 0 );
}
Well, at least this compiles... I'm not game to run it, though...
For what it's worth...
enum sid { DRB, DRA, DRAwhoCares };
typedef struct {
unsigned int r;
unsigned int *p;
} oneD_t;
typedef struct {
oneD_t *a;
enum sid z;
} twoD_t;
unsigned int getSmg( twoD_t *smg ) {
unsigned int c = 0;
for( twoD_t *sd = smg; sd->a != NULL; +sd++ ) {
for( oneD_t *ed = sd->a; ed->p != NULL; ed++ ) {
if( DRA == sd->z ) {
/*P Increment the clear-state buffer size */
c += 1 + ed->r;
}
}
}
return c;
}
int main( void ) {
oneD_t foo[] = { { 1, NULL }, /* ... */ };
oneD_t bar[] = { { 1, NULL }, /* ... */ };
twoD_t smg[]={
{ foo, DRA, },
{ bar, DRA, },
{ NULL, DRAwhoCares, },
};
unsigned int rVal = getSmg( smg );
printf( "Return value: %u\n", rVal );
return 0; // return is not a function call... No parenthesis...
}

Using qsort() with Structs

I just started learning C and I'm still new to it.
In this program I'm working with an array of structs. The structs are:
typedef struct {
int day;
int month;
int year;
} Date;
typedef struct {
int serial_num;
char full_name[15];
Date *pDate;
} Person;
The array is Person *people.
Now I have two arrays of people and birth dates of those people (same indexes):
const char* names[MAX] = { "Sasson_Sassoni", "Pooh", "James_Bond", "Elvis_is_Alive", "Shilgiya", "Cleopatra", "Sissoo_VeSimmhoo" };
const int dates[MAX][COLS] = {
{ 10, 1, 1988 },
{ 12, 12, 1948 },
{ 4, 12, 1970 },
{ 11, 11, 1890 },
{ 11, 11, 1948 },
{ 1, 10, 1213 },
{ 12, 11, 1948 }
};
By using switch case, every time the user types 1 a person from the lists (Name and birthday) is added to the list people. Then if the user types 3, the list people should be sorted by date (oldest to youngest). So I wrote the following two functions:
void sortList(Person **people, int index) {
qsort(*people, index, sizeof(Person), intcmp);
}
int intcmp(const void *a, const void *b) {
Person *one = (Person *)a;
Person *two = (Person *)b;
int year1 = one->pDate->year;
int year2 = two->pDate->year;
int month1 = one->pDate->month;
int month2 = two->pDate->month;
int day1 = one->pDate->day;
int day2 = two->pDate->day;
if (year1 > year2)
return -1;
else if (year2 > year1)
return 1;
if (month1 > month2)
return -1;
else if (month2 > month1)
return 1;
if (day1 > day2)
return -1;
else if (day2 > day1)
return 1;
return 0;
}
But every time I get an error saying:
Exception thrown: read access violation.
one->pDate was nullptr.
Any help?
Thanks!
EDIT:
Further explanation: In order to insert the people to the array one by one, I made a variable called index and every time a person is added the index grows by one. So When calling the function qsort(), index is the number of people in the array. Also MAX=7, COLS=3, LEN=10. The function that adds people to the array is:
void addToList(Person **people, int *index, const char *names[MAX], const int dates[][COLS]) {
people[*index] = (Person *)malloc(sizeof(Person));
people[*index]->serial_num = *index + 1;
strcpy(people[*index]->full_name, names[*index]);
Date *temp = (Date *)malloc(sizeof(Date));
temp->day = dates[*index][0];
temp->month = dates[*index][1];
temp->year = dates[*index][2];
people[*index]->pDate = temp;
printf("%d %s %d/%d/%d \n", people[*index]->serial_num, people[*index]->full_name, people[*index]->pDate->day, people[*index]->pDate->month, people[*index]->pDate->year);
*index = *index + 1;
}
Your mcve is not complete but I think it's because you confuse pointer and struct:
void sortList(Person **people, int index) {
qsort(people, index, sizeof(Person *), intcmp);
// or qsort(people, index, sizeof *people, intcmp);
}
int intcmp(const void *a, const void *b) {
const Person *one = *(const Person **)a;
const Person *two = *(const Person **)b;

Relocating a Node in a Singly Linked List Creates Infinite Loop

In my homework I was asked to relocate a specific node by his name field to specific index. I'm having trouble to figure out why is my list becomes an infinite list. The problem is in the function "changePlacement" Example: Given linked list : 1->2->3->4 Output : 1->3->3->3... Expected output : 1->3->2->4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Frame
{
char *name;
unsigned int duration;
char *path; // may change to FILE*
};
typedef struct Frame frame_t;
struct Link
{
frame_t *frame;
struct Link *next;
};
typedef struct Link link_t;
int listLen = 0;
link_t* lastNode = NULL;
void addFrame(link_t** list);
void frameData(frame_t* frame);
void freeVideo(link_t* video);
void showList(link_t* list);
void freeNode(link_t* list);
void changePlacement(link_t** list, int newIndex, char* name);
int main(void)
{
link_t* video = NULL;
lastNode = video;
if (!video)
{
perror(video);
}
addFrame(&video);
addFrame(&video);
addFrame(&video);
addFrame(&video);
showList(video);
changePlacement(&video, 2, "3");
showList(video);
printf("\n");
freeVideo(&video);
_flushall();
getchar();
return 0;
}
void addFrame( link_t** video)
{
char strTemp[200] = { 0 };
link_t* newFrame = (link_t*) calloc(1, sizeof(link_t));
newFrame->frame = (frame_t*) malloc(sizeof(frame_t));
printf(" *** Creating new frame ***\n");
printf("Please insert a frame path:\n");
scanf(" %s", &strTemp);
newFrame->frame->path = (char*) calloc(strnlen(strTemp, 200) + 1, sizeof(char));
strncpy(newFrame->frame->path, strTemp, strnlen(strTemp, 200));
printf("Please insert frame duration(in miliseconds):\n");
scanf(" %d", &(newFrame->frame->duration));
printf("Please choose a name for that frame:\n");
scanf(" %s", &strTemp);
newFrame->frame->name = (char*) calloc(strnlen(strTemp, 200) + 1, sizeof(char));
strncpy(newFrame->frame->name, strTemp, strnlen(strTemp, 200));
if (!(*video))
{
(*video) = newFrame;
}
else
{
lastNode->next = newFrame;
}
lastNode = newFrame;
++listLen;
}
void freeVideo(link_t** video)
{
link_t* currNode = NULL;
int loop = 0;
for (; currNode; currNode = *video) // set curr to head, stop if list empty.
{
// advance head to next element.
freeNode(currNode);
(*video) = (*video)->next; // delete saved pointer.
}
freeNode((*video)->next);
freeNode((*video));
}
void showList(link_t* list)
{
printf("\n\t|Name\t\t| Duration | Path\n");
printf("\t+++++++++++++++++++++++++++++++++++++++++++++++\n");
for (;list; list = list->next)
{
printf("\t|%10s\t|%10d\t|\t%s\n", list->frame->name, list->frame->duration, list->frame->path);
printf("\t+++++++++++++++++++++++++++++++++++++++++++++++\n");
}
}
void freeNode(link_t* node)
{
free(node->frame->name);
free(node->frame->path);
free(node->frame);
free(node);
}
void changePlacement(link_t** list, int newIndex, char* name)
{
link_t *prevOldNode = (*list), *prevTemp = NULL, *oldNode = NULL, *newNode = NULL;
link_t *temp = (*list), *PrevNewNode = NULL, *nodeAfterNewNode = NULL;
int currIndex = 0, i = 0, flag = 0;
while ((temp->next))
{
++currIndex;
if (!strcmp(temp->frame->name, name)) //looking for the wanted node
{
oldNode = temp;
prevOldNode = prevTemp;
}
if (currIndex == newIndex)
{
PrevNewNode = prevTemp;
newNode = temp;
}
prevTemp = temp;
temp = temp->next;
}
nodeAfterNewNode = newNode->next; //temporal variable that stores the node after the new node
prevOldNode->next = oldNode->next;
newNode->next = oldNode;
oldNode->next = nodeAfterNewNode;
}
Do you have any ideas after looking on my code? any help would be blessed
Your code at the end of changePlacement() doesn't account for the case of oldNode and newNode being adjacent to each other, i. e. e. g. nodeAfterNewNode = newNode->next being identical to oldNode. (Besides it doesn't account for the case of not finding the name.) It is far easier to just exchange the frame pointers; change
nodeAfterNewNode = newNode->next; //temporal variable that stores the node after the new node
prevOldNode->next = oldNode->next;
newNode->next = oldNode;
oldNode->next = nodeAfterNewNode;
to
if (!oldNode) return; // wanted node name not found
frame_t *f = oldNode->frame;
oldNode->frame = newNode->frame;
newNode->frame = f;

Member reference type issue

Hi everyone I'm having a problem with my code and I really don't know how to fix it.
It's telling me that member reference type 'Word'(aka 'struct dict_word *') is not a structure or a union.
I'm trying to change my struct dict_word to word as as you can see on my typedef but when I do it it's giving me that error.
Please have a look at my code I would really appreciate if you could explain that to me.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dict_word *word;
typedef struct node *Node;
typedef struct double_linked_list *DLL;
struct dict_word
{
char words[100];
int year[10];
char eng_synonyms[100];
char heb_synonyms[100];
};
struct node
{
word data;
Node *next;
Node *previous;
};
struct double_linked_list
{
Node *head;
Node *last;
};
int SpliString(struct dict_word* entry, const char *str) // Here is where I'm trying to change struct dict_node to word
{
long sz,j,k;
int yearIndex;
char *buffer;
char *endOfYears;
char *endOfYear;
char *endOfDefinition;
char *endOfWord = strstr(str, "_#_");
//Sets the first num bytes of the block of memory pointed by ptr
//to the specified value (related as an unsigned char)
memset(entry, 0, sizeof(struct dict_word));
if (endOfWord)
{
sz = endOfWord - str;
strncpy(entry->words, str, sz);
endOfYears = strstr(endOfWord+3, "_#_");
if (endOfYears)
{
sz = endOfYears - (endOfWord+3);
buffer = endOfWord+3;
yearIndex = 0;
j = 0;
while(yearIndex<10 && buffer+j<endOfYears)
{
entry->year[yearIndex] = atoi(buffer+j);
// check year for negative...
if (entry->year[yearIndex]<=0)
return 0;
// Locating substring
endOfYear = strchr(buffer+j, '_');
if (endOfYear)
{
j = endOfYear - buffer;
j++;
yearIndex++;
}
else
{
break;
}
}
endOfDefinition = strstr(endOfYears+3, "_#_");
if (endOfDefinition)
{
sz = endOfDefinition - (endOfYears+3);
k = 0;
for(j=0; j<sz; j++)
{
if (endOfYears[j+3]==',') //Q11: what's j+3?
//A11: skips _#_
{
entry->eng_synonyms[k] = ' ';
k++;
}
else if (endOfYears[j+3]>='a' && endOfYears[j+3]<='z')
{
entry->eng_synonyms[k] = endOfYears[j+3];
k++;
}
else if (endOfYears[j+3]!='_')
{
return 0;
}
}
k = 0;
sz = (str+strlen(str)) - (endOfDefinition+3);
for(j=0; j<sz; j++)
{
if (endOfDefinition[j+3]==',')
{
entry->heb_synonyms[k] = ' ';
k++;
}
else if (endOfDefinition[j+3]>='A' && endOfDefinition[j+3]<='Z')
{
entry->heb_synonyms[k] = endOfDefinition[j+3];
k++;
}
else if (endOfDefinition[j+3]!='_')
{
return 0;
}
}
}
// check for legality
for(j=0;j<(int)strlen(entry->words);j++)
{
if (entry->words[j]<'a' || entry->words[j]>'z')
return 0;
}
return 1;
}
}
return 0;
}

Setting struct value = segfault

#include <stdio.h>
#include <stdlib.h>
#define true 1
struct hashRow {
char *key;
char *value;
};
struct hash_table {
int max;
int number_of_elements;
struct hashRow **elements;
};
int hashstring(const char *s)
{
int key = 0;
while (*s)
key = key * 37 + *s++;
return key;
}
int hash_fun(int key, int try, int max) {
return (key + try) % max;
}
struct hash_table *table;
int hash_insert(struct hashRow *data, struct hash_table *hash_table) {
int try, hash;
if(hash_table->number_of_elements < hash_table->max) {
return 0; // FULL
}
for(try = 0; true; try++) {
int hkey = hashstring(data->key);
hash = hash_fun(hkey, try, hash_table->max);
if(hash_table->elements[hash] == 0) { // empty cell
hash_table->elements[hash] = data;
hash_table->number_of_elements++;
return 1;
}
}
return 0;
}
struct hashRow *hash_retrieve(char *key, struct hash_table *hash_table) {
int try, hash;
for(try = 0; true; try++) {
int hkey = hashstring(key);
hash = hash_fun(hkey, try, hash_table->max);
if(hash_table->elements[hash] == 0) {
return 0; // Nothing found
}
if(hash_table->elements[hash]->key == key) {
return hash_table->elements[hash];
}
}
return 0;
}
int hash_delete(char *key, struct hash_table *hash_table) {
int try, hash;
for(try = 0; true; try++) {
int hkey = hashstring(key);
hash = hash_fun(hkey, try, hash_table->max);
if(hash_table->elements[hash] == 0) {
return 0; // Nothing found
}
if(hash_table->elements[hash]->key == key) {
hash_table->number_of_elements--;
hash_table->elements[hash] = 0;
return 1; // Success
}
}
return 0;
}
void insertsomething()
{
struct hashRow *toInsert;
toInsert = (struct hashRow *)malloc(sizeof(*toInsert));
printf("toInsert declared\n");
char *k = (char*)malloc(sizeof(char*));
char *v = (char*)malloc(sizeof(char*));
k = "sayhello";
v = "hello";
this is where I seem to be having the problem.
toInsert->key = k;
toInsert->value = v;
hash_insert(toInsert, table);
}
int main()
{
printf("calling insertsomething.\n");
insertsomething();
struct hashRow *gotten;
gotten = hash_retrieve("sayhello", table);
printf("test: %s\n", gotten->value);
}
I'm trying to create a hash table, but whenever I try to set a value in the toInsert struct pointer it segfaults. Can someone explain to me what I am doing wrong?
Try this:
void insertsomething()
{
struct hashRow *toInsert;
toInsert = (struct hashRow *)malloc(sizeof(*toInsert));
printf("toInsert declared\n");
/*
char *k = (char*)malloc(sizeof(char*)); // wrong size
char *v = (char*)malloc(sizeof(char*)); // wrong size
k = "sayhello"; // bad assignment
v = "hello"; // bad assignment
*/
toInsert->key = strdup("sayhello");
toInsert->value = strdup("hello");
hash_insert(toInsert, table);
}
Also, I can't spot where you reserve memory for your hash_table. Is it hidden somewhere else??

Resources