Some starters:
creating a dynamic array of a data structure called fractions.
Fractions has functions for setting, printing, intiting etc.
I kept getting an error for double freeing or corruption, along with a lot of gibberish from the memory map. This is the error from the output:
double free or corruption (top): 0x0000000001976010 *
I get that it is being freed/deleted twice but here is the code that generates the error:
#include <stdio.h>
#include <stdlib.h>
#include "fraction.h"
main() {
long long int size = 0;
long long int capacity = 10;
int FSize = sizeof(struct fraction);
struct fraction* array = NULL;
struct fraction in;
array = (struct fraction*)malloc(FSize * capacity);
if (array == NULL) {
printf("MALLOC DID NOT WORK\n");
exit(1);
}
int i = 0;
for (i = 0; i < 17; i++) {
if (size == capacity) {
capacity = capacity * 2;
struct fraction* temp = NULL;
temp = (struct fraction*)realloc(array, FSize * capacity);
// free(array);
array = temp;
free(temp);
}
SetFrac(&in);
array[size++] = in;
}
printf("IT MADE IT HERE >>>>>>>>>>>>>>>>>> \n");
getchar();
for (i = 0; i < size; i++) {
struct fraction t = array[i];
PrintFrac(&t);
}
free(array);
return 0;
}
Here is the code that works
#include <stdio.h>
#include <stdlib.h>
#include "fraction.h"
main() {
long long int size = 0;
long long int capacity = 10;
int FSize = sizeof(struct fraction);
struct fraction* array = NULL;
struct fraction in;
array = (struct fraction*)malloc(FSize * capacity);
if (array == NULL) {
printf("MALLOC DID NOT WORK\n");
exit(1);
}
int i = 0;
for (i = 0; i < 17; i++) {
if (size == capacity) {
capacity = capacity * 2;
struct fraction* temp = NULL;
temp = (struct fraction*)realloc(array, FSize * capacity);
// free(array);
array = temp;
free(temp);
}
SetFrac(&in);
array[size++] = in;
}
printf("IT MADE IT HERE >>>>>>>>>>>>>>>>>> \n");
getchar();
for (i = 0; i < size; i++) {
struct fraction t = array[i];
PrintFrac(&t);
}
// free(array);
return 0;
}
Am I using the free() function wrong?
array and temp have the same pointer address, so when you free temp, array will be freed also
You should only free "array" at the end. You must not free "temp", because you'll continue using the block (array = temp does not maintain a certain "reference count", but simply assigns a pointer).
After calling free, you should not dereference the freed memory, which you are doing by using array[size++].
You should not free() on temp there, because you are using array later.
Your final commented out free() would be the only one that would be correct, although the program should run fine with out it.
You don't need to free(temp) after realloc temp, just to free(array) the end of main. If you realloc is success,two possibilities:
temp == array (temp point to the same memory)
array is free and temp point to a new memory
Related
Can we dynamically allocate memory for structures? Is this a correct procedure to approach a dynamically allocated structures? Please tell me how to malloc() and realloc() a structure.
newnode is of type struct List * but when start indexing it converts to struct List.How this conversion possible?My insert function accepts only (struct List*) Am I wrong somewhere?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct List {
char val[20];
};
void insert(struct List *);
int main(void) {
int i = 0;
int size = 1;
struct List *newnode = (struct List *)malloc(size * sizeof(struct List));
for (i = 0; i < 5; i++) {
if (size <= i) {
size = size + size;
newnode = (struct List *)realloc(newnode, size * sizeof(struct List));
}
scanf("%s", newnode[i].val);
insert(newnode[i]);
}
for (i = 0; i < 5; i++) {
printf("%s\n", newnode[i].val);
}
return 0;
}
void insert(struct List *node) {
printf("%s\n", node->val);
}
The code works except for 3 problems:
You do not test for memory allocation failure. Both malloc() and realloc() will return NULL if memory cannot be allocated: you will get undefined behavior when dereferencing newnode should this happen.
to handle the case of realloc() failure gracefully, you should store the reallocated pointer to a different variable so you can still access the previous array that has not been deallocated and free it.
scanf("%s", newnode[i].val); is a security flaw: you should limit the number of bytes that can be stored to the destination array with
scanf("%19s", newnode[i].val);
you do not test the return value of scanf() to detect invalid or missing input.
insert() does not insert anything.
Here is a modified version with error handling and less confusing names:
#include <stdio.h>
#include <stdlib.h>
struct Item {
char val[20];
};
//void insert(struct Item *);
int main(void) {
int i, j;
int size = 0;
struct Item *array = NULL;
for (i = 0; i < 5; i++) {
if (i >= size) {
int newsize = size ? 1 : size + size;
struct Item *newarray = realloc(array, sizeof(*array) * size);
if (newarray == NULL) {
perror("cannot reallocate the array");
break;
}
size = newsize;
array = newarray;
}
if (scanf("%19s", array[i].val) != 1) {
fprintf(stderr, "missing input\n");
break;
}
//insert(array[i]);
}
for (j = 0; j < i; i++) {
printf("%s\n", array[i].val);
}
free(array);
return 0;
}
Yes, this is fine except that you are assigning the return value to your original array pointer. realloc() returns NULL if it can't resize the memory. You need to assign it to a temporary variable and, if the value is NULL, don't overwrite a.
The main thing you have to watch out for are pointers, which your struct doesn't have. In those cases, the memory pointed to is not part of the allocated array.
I made a hashtable, and it runs fine, but when i run it with valgrind,it tells me there is memory leaks when creating the hashtable and a memory leak for every user insertion, 12 bytes per insertion and 40 for creating the hashtable
here is some testable code:
#include <malloc.h>
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#define initial_size 5
typedef struct user_pos {
char nick[6];
int position_in_file;
}user_pos;
typedef struct bucket{
user_pos *info;
}bucket;
typedef struct hashtable{
int size;
int elements;
bucket **buckets;
}hashtable;
unsigned hash(char *s) {
unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31*hashval;
return hashval;
}
hashtable * create() {
hashtable *htable;
if((htable = malloc(sizeof(hashtable))) == NULL)
return NULL;
if((htable->buckets = malloc(sizeof(bucket) * initial_size)) == NULL)
return NULL;
htable->size = initial_size;
htable->elements = 0;
for(int i=0; i < initial_size; i++){
htable->buckets[i] = NULL;
}
return htable;
}
void insert(hashtable *hashtable, char *nick, int position_in_file){
int hash_value = hash(nick);
int new_position = hash_value % hashtable->size;
if (new_position < 0) new_position += hashtable->size;
int position = new_position;
while (hashtable->buckets[position] != NULL && position != new_position - 1) {
if(hashtable->buckets[position]->info != NULL){
position++;
position %= hashtable->size;
}else{
break;
}
}
hashtable->buckets[position] = malloc(sizeof(bucket));
hashtable->buckets[position]->info = malloc(sizeof(user_pos));
strcpy(hashtable->buckets[position]->info->nick, nick);
hashtable->buckets[position]->info->position_in_file = position_in_file;
hashtable->elements++;
}
void delete_hashtable(hashtable *ht) {
for(int i = 0; i<ht->size; i++){
if(ht->buckets[i] != NULL && ht->buckets[i]->info != NULL)
free(ht->buckets[i]);
}
free(ht);
}
int main(){
hashtable *ht = create();
insert(ht, "nick1", 1);
insert(ht, "nick2", 2);
delete_hashtable(ht);
return 0;
}
I am initializing a bucket everytime i insert a new item, but i think i cant free it after, because that would erase what was just added, the same for the create() function.
How do i avoid leaking memory in this case?
Thanks in advance.
The memory leak is not in your allocation function but in the cleanup. You fail to free everything you allocated in delete_hashtable.
You clean up ht->buckets[i] and ht, but fail to clean up ht->buckets[i]->info and ht->buckets. You need to free those as well:
void delete_hashtable(hashtable *ht) {
for(int i = 0; i<ht->size; i++){
if(ht->buckets[i] != NULL && ht->buckets[i]->info != NULL)
free(ht->buckets[i]->info);
free(ht->buckets[i]);
}
free(ht->buckets);
free(ht);
}
Also, you're allocating the wrong number of bytes for htable->buckets:
if((htable->buckets = malloc(sizeof(bucket) * initial_size)) == NULL)
Each element is a bucket *, not a bucket, so that's the size you should use:
if((htable->buckets = malloc(sizeof(bucket *) * initial_size)) == NULL)
Or better yet:
if((htable->buckets = malloc(sizeof(*htable->buckets) * initial_size)) == NULL)
That way it doesn't matter what the type of htable->buckets is or if you change it later.
I'm trying to build an arraylist in C with the following code
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Declaration of ArrayList structure
typedef struct ArrayList {
int length, capacity;
int *items;
} ArrayList;
// Create a new ArrayList
ArrayList *newList() {
int *items = malloc(4 * sizeof(int));
ArrayList *list = malloc(sizeof(ArrayList));
list->length = 0;
list->capacity = 4;
list->items = items;
return list;
}
// Check and expand list if neccessary
void check(ArrayList *list) {
printf("Check called (%d, %d)\n", list->length, list->capacity);
if (list->length >= list->capacity) {
printf("Expanding\n");
list->capacity = list->capacity * 2;
printf("Reallocating\n");
list->items = realloc(list->items, list->capacity);
if (list->items == NULL) {
printf("realloc failed\n");
exit(1);
}
}
}
// Add a value to the ArrayList
void add(ArrayList *list, int n) {
check(list);
list->items[list->length] = n;
list->length++;
}
// Print the list
void printList(ArrayList *list) {
for (int i=0; i<list->length; i++) {
if (i > 0) printf(", ");
printf("%d", list->items[i]);
}
printf("\n");
}
int main () {
ArrayList *list = newList();
for (int i = 0; i < 20; i++) {
add(list, i);
}
printList(list);
}
When the array is full, the check function is called as it should be. However, the second time the check function is called, the program failes on the call to realloc giving the following error:
*** Error in `./test': realloc(): invalid next size: 0x0000000001d3c010 ***
Aborted (core dumped)
where the size varies every time the program is run.
I have read that this error is caused by a corrupt heap, which is normally caused by pointers going wrong somewhere. However, I cannot see where the problem lies in this example. Any help would be appreciated.
you are reallocating the list->items. realloc() function has 2 parameter
first one is void pointer ,this point to the memory block that previously allocated,and second parameter works for how many bytes have to reallocate.
in your code you added only the capacity...bt it is not .u have to add size of the int with capacity ...cause it only takes (size ) int byte ...
then it works fine
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// Declaration of ArrayList structure
typedef struct ArrayList {
int length, capacity;
int *items;
} ArrayList;
int i;
// Create a new ArrayList
ArrayList *newList() {
int *items = malloc(4 * sizeof(int));
ArrayList *list = malloc(sizeof(ArrayList));
list->length = 0;
list->capacity = 4;
list->items = items;
return list;
}
// Check and expand list if neccessary
void check(ArrayList *list) {
printf("Check called (%d, %d)\n", list->length, list->capacity);
if (list->length >= list->capacity) {
printf("Expanding\n");
list->capacity = list->capacity * 2;
printf("Reallocating\n");
list->items = realloc(list->items, list->capacity * sizeof(int));
if (list->items == NULL) {
printf("realloc failed\n");
exit(1);
}
}
}
// Add a value to the ArrayList
void add(ArrayList *list, int n) {
check(list);
list->items[list->length] = n;
list->length++;
}
// Print the list
void printList(ArrayList *list) {
for (i=0; i<list->length; i++) {
if (i > 0) printf(", ");
printf("%d", list->items[i]);
}
printf("\n");
}
int main () {
ArrayList *list = newList();
for ( i = 0; i < 20; i++) {
add(list, i);
}
printList(list);
}
I am trying to take input from console and add it to hash table.
But I'm getting Segmentation fault 11.
So, I debugged the program using gdb-apple.
It is showing that I'm trying access memory I cannot, using the pointer variable.
I think it is something obvious, but I'm missing it
This is what the gdb is displaying
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000008
0x0000000100000986 in CreateHashTable (size=200) at hashing.c:29
29 h->Table[i]->next = NULL;
Here is the code
Header File:
#define LOAD_FACTOR 20
#define INITIAL_SIZE 200
struct HashTable *CreateHashTable(int size);
int HashSearch(struct HashTable *h,int data);
int HashInsert(struct HashTable *h,int data);
int HashDelete(struct HashTable *h, int data);
void Rehash(struct HashTable *h);
int Hash(int data, int size);
struct ListNode
{
int key;
int data;
struct ListNode *next;
};
struct HashTableNode
{
int bcount;
struct ListNode *next;
};
struct HashTable
{
int tsize;
int count;
struct HashTableNode **Table;
};
Implementation file:
#include "hashing.h"
#include<stdio.h>
#include<stdlib.h>
struct HashTable *CreateHashTable(int size)
{
struct HashTable *h;
h = (struct HashTable *) malloc ( sizeof(struct HashTable) );
if(h == NULL)
{
printf("Memory Error");
return NULL;
}
h->tsize = (int) size/LOAD_FACTOR;
printf("h->tsize = %d",h->tsize);
h->count = 0;
h->Table = malloc ( ( sizeof(struct HashTableNode **) ) * (h->tsize) );
if( h->Table == NULL )
{
printf("Memory Error");
return NULL;
}
int i;
for( i=0 ; i < (h->tsize) ; i++)
{
h->Table[i]->next = NULL;
h->Table[i]->bcount = 0;
}
return h;
}
I would paste the rest of file, or Driver file, but I don't see it relevant.
Please tell me why I'm getting the segmentation fault 11
You allocated memory for array of pointers but you didn't allocate memory for members of this array.
for( i=0 ; i < (h->tsize) ; i++)
{
h->Table[i] = malloc(...); //put correct arguments here and check allocation
h->Table[i]->next = NULL;
h->Table[i]->bcount = 0;
}
Your problem is here:
struct HashTableNode **Table;
You want an array of nodes (not a 2d array), change to:
struct HashTableNode *Table;
also change
h->Table = malloc ( ( sizeof(struct HashTableNode **) ) * (h->tsize) );
to
h->Table = malloc(sizeof(struct HashTableNode) * h->tsize);
I think I want an array of pointers to nodes, don't I?
As pointed out by #WhozCraig, there is no reason for the additional level of indirection.
Example A (Pointer):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *a; /* pointer */
int i, n = 10;
a = malloc(n * sizeof(int)); /* space for 10 ints */
for (i = 0; i < n; i++) {
a[i] = i;
}
for (i = 0; i < n; i++) {
printf("%d\n", a[i]);
}
free(a);
return 0;
}
Example B (Pointer to pointer):
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int **a; /* pointer to pointer*/
int i, n = 10;
a = malloc(n * sizeof(int *)); /* space for 10 pointer to ints */
for (i = 0; i < n; i++) {
a[i] = malloc(sizeof(int)); /* space for 1 int */
*a[i] = i;
}
for (i = 0; i < n; i++) {
printf("%d\n", *a[i]);
free(a[i]);
}
free(a);
return 0;
}
As you can see both do the same thing, but the first one requires less memory and the code is cleaner.
One way to make it easy to remember is:
int * can hold an array
int ** can hold a table (NROWS * NCOLS)
int *** can hold an array of tables
I wrote a piece of code to handle dynamic arrays. Idea was to use array of struct pointers, where the last member of array is NULL. Slight variation of code I wrote is below (using integers and not structures).
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
void list_add(int **list, int* value) {
for(int i = 0; true; i++) {
if(list[i] == NULL) {
list = realloc(list, (i+2) * sizeof(int*));
list[i] = value;
list[i+1] = NULL;
break;
}
}
}
void list_init(int **list) {
int* x;
for(int i = 0; i < 100; i++) {
x = malloc(sizeof(int));
*x = i;
list_add(list, x);
}
}
int main() {
int** l = malloc(sizeof(int*));
l[0] = NULL;
list_init(l);
}
While debugging, I discovered that only first 3 integers are added to the list. I can't seem to figure out why is this happening. Any ideas?
The problem is that the call to realloc() in list_add() potentially frees the memory block *list and allocates another. list_add updates its list pointer, but it does not return the updated pointer to the caller, list_init(); list_init()'s list pointer is potentially a pointer to the recently-freed memory block.
To fix this code, list_add() and list_init() need to be able to "return" the updated list pointer:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
void list_add(int ***p_list, int *value) {
int **list = *p_list;
int i;
for(i = 0; true; i++) {
if(list[i] == NULL) {
list = realloc(list, (i+2) * sizeof(int*));
list[i] = value;
list[i+1] = NULL;
break;
}
}
*p_list = list;
}
void list_init(int ***p_list) {
int **list = *p_list;
int *x;
int i;
for(i = 0; i < 100; i++) {
x = malloc(sizeof(int));
*x = i;
list_add(&list, x);
}
*p_list = list;
}
int main() {
int **list = malloc(sizeof(int*));
list[0] = NULL;
list_init(&list);
int **l = list;
for (; *l != NULL; ++l) {
printf("%d\n", **l);
}
}
http://codepad.org/iGcSaJOR
EDIT
In this case of dynamic arrays the way you have told will not make anything better, the code will complicate only. For each addition of integer you have used realloc trying aggressively to save memory, but this will take more time while execution. Why not allocate a block of memory reserved for the array and to reflect the dynamic character put the array inside a struct with the last index, and when you add something add it on the last location and increment the counter. When this block is filled, you can chain another block to point to another one.
typedef struct _dyna_arr
{
my_type data_arr[MAX_LEN];
int n;
struct _dyna_arr *next block;
};
Therefore you maintain a linked list of multiple arrays. The size of MAX_LEN can be fixed which is appropriate for an application which will help decrease internal fragmentation.
*old answer removed *