Implementing a generic arraylist in C [duplicate] - c

This question already has an answer here:
Making a generic ArrayLIst in C
(1 answer)
Closed 2 years ago.
I am trying to implement a java-like arraylist in C and now I am trying to make it generic. I am new to C and pointer arithmetic but I tried using void* pointer for container, then element size(for size of data type), capacity and size. I am trying to debug my code and it is giving a random value on the screen.
I cant seem to find what is wrong with my add method ? and how should I go about the printlist method as we are not sure about the data type. I think my printLIst is wrong.
I am new to C and playing around for educational purposes and any help is appreciated. Thank you
____________________________________________________________________
#ifndef ARRAYLIST_H
#define ARRAYLIST_H
typedef struct ArrayList ArrayList;
typedef int bool;
#define false 0
#define true 1
struct ArrayList {
void *con;
int elementSize;
int numElements;
int conSize;
};
ArrayList *createArrayList(int );
int remove(ArrayList *, int);
void freeArrayList(ArrayList *);
int add(ArrayList *, void*);
void *getAtIndex(ArrayList *, int);
void printList(ArrayList *);
void resize(ArrayList *);
bool isEmpty(ArrayList*);
int getNumElements(ArrayList*);
int getConSize(ArrayList*);
#endif
_______________________________________________________________________
#include<stdio.h>
#include<stdlib.h>
#include"Consts.h"
#include<memory.h>
#include "ArrayList.h"
#define CAPACITY 5
#define EXTRA 100
ArrayList *createArrayList(int elementSize) {
ArrayList *arrayList = malloc(sizeof(ArrayList));
arrayList->elementSize = elementSize;
arrayList->conSize = CAPACITY;
arrayList->numElements = 0;
arrayList->con = malloc(elementSize * CAPACITY);
return arrayList;
}
void freeArrayList(ArrayList * arrayList) {
if (arrayList == NULL) {
return;
}else {
free(arrayList->con);
free(arrayList);
}
}
int add(ArrayList *list, void *input) {
if (list != NULL && input != NULL) {
if (list->numElements >= list->conSize) {
resize(list);
printf("resized\n");
}
list->con = input;
memcpy((char*)list->con + (list->numElements*list->elementSize), input, list->elementSize);
list->numElements++;
return 1;
}
return -1;
}
void resize(ArrayList *list) {
void *temp = realloc(list->con, (list->conSize + EXTRA) * list->elementSize);
if (temp != NULL) {
list->conSize += 100;
list->con = temp;
}
}
int remove(ArrayList * list, int i) {
if (list != NULL) {
//find index of value to remove
int elementSize = list->elementSize;
int lenToMove = elementSize * (list->numElements - (i + 1));
memmove((char *)list->con + i*elementSize, (i+1)*elementSize, lenToMove);
list->numElements--;
return 1;
}
return -1;
}
void printList(ArrayList *list) {
if (list != NULL) {
char *p = list->con;
for (int i = 0; i < list->numElements; i++) {
void* val = getAtIndex(list, i);
printf("%d \n", val);
}
}
}
void *getAtIndex(ArrayList *listptr, int index) {
return (char*)listptr->con + index * (listptr->elementSize);
}
int getNumElements(ArrayList * list) {
return list->numElements;
}
int getConSize(ArrayList * list) {
return list->conSize;
}
bool isEmpty(ArrayList * list) {
return list->numElements == 0;
}
___________________________________________________
#include<stdio.h>
#include<stdlib.h>
#include"ArrayList.h"
#include "Consts.h"
#pragma warning(disable : 4996)
int main() {
ArrayList * list = createArrayList(sizeof(int));
int x = 5;
add(list, &x);
printf("%d",(int *)getAtIndex(list, 0));
freeArrayList(list);
system("pause");
return 0;
}

Pay attention to the comments above. I know you're new to the site, but it's worth while getting to know how it works.
Anyway the problem is in this line of code:
printf("%d",(int *)getAtIndex(list, 0));
getAtIndex() returns a pointer so you need to dereference it to get the value. It should be:
printf("%d",*(int *)getAtIndex(list, 0));

Related

Generic ArrayList in C

I have made a Java like ArrayList class in C for educational purposes however currently it is only good for integers. I want to make it Generic so it can take any type of data. How do I go about it. I read somewhere about creating a typedef void pointer. Any thoughts ?
........................................................................................................
Here is My code
#ifndef ARRAYLIST_H
#define ARRAYLIST_H
typedef struct ArrayList ArrayList;
typedef int bool;
#define false 0
#define true 1
struct ArrayList {
int *con;
int numElements;
int conSize;
};
ArrayList *createArrayList();
void freeArrayList(ArrayList *);
void add(ArrayList *, int);
void printList(ArrayList *);
void resize(ArrayList *);
int remove(ArrayList *, int);
bool isEmpty(ArrayList*);
int getNumElements(ArrayList*);
int getConSize(ArrayList*);
#endif
_____________________________________
#include<stdio.h>
#include<stdlib.h>
#include"Consts.h"
#include "ArrayList.h"
#define CAPACITY 5
ArrayList *createArrayList() {
ArrayList *arrayList = malloc(sizeof(ArrayList));
arrayList->conSize = CAPACITY;
arrayList->numElements = 0;
arrayList->con = malloc(sizeof(int) * CAPACITY);
return arrayList;
}
void freeArrayList(ArrayList * arrayList) {
if (arrayList == NULL) {
return;
}else {
free(arrayList->con);
free(arrayList);
}
}
void add(ArrayList *arrayList, int input) {
//printf("Num elements in add method before adding %d \n", arrayList->numElements);
if (arrayList->numElements >= arrayList->conSize) {
resize(arrayList);
printf("resized\n");
}
int size = arrayList->numElements;
//add element to the last
arrayList->con[size] = input;
arrayList->numElements = arrayList->numElements + 1
}
void resize(ArrayList *arrayList) {
int num = arrayList->numElements;
int oldSize = arrayList->conSize;
int newSize = oldSize + 50;
int *temp = realloc(arrayList->con, sizeof(type) * newSize);
if (temp != NULL) {
arrayList->con = temp;
arrayList->conSize = newSize;
}
}
int remove(ArrayList * arrayList, int val) {
int i = 0;
while (arrayList->con[i] != val) {
i++;
}
//remove this index
if (i == arrayList->conSize) {
return -1;
}
else {
int removedVal = arrayList->con[i]; int j;
for (j = i; j < arrayList->numElements ; j++) {
arrayList->con[j] = arrayList->con[j + 1];
}
arrayList->con[j + 1] = NULL;
arrayList->numElements = arrayList->numElements - 1;
return removedVal;
}
}
If you want the array list be able to store any type of data, you need to
1) make con a void pointer. void *con;
2) store additional metadata in the struct about the memory alignment of the type
3) add one more parameter to the constructor of array list, which is the additional metadata mentioned in 2)
4) when allocating memory, use the stored metadata instead of sizeof(whatever), like temp=malloc(stored_metadata_about_type*50);
Also notice that it is not usually a good idea to hardcode 50, and better declare it as a constant like buffer_size.

Printing arraylist size crash

I have a C program that implement arraylist (dynamic array,however I dont understand how or why i cannot print the array size.When I try to do so, the program just crash.Heres the program.
arraylist.c
#include "arraylist.h"
void arraylist_initial(struct arraylist *list) {
list->size = 0;
list->data = NULL;
}
int arraylist_get_size(const struct arraylist list) {
return list.size;
}
value_type* arraylist_get_data_collection(const struct arraylist list) {
return list.data;
}
void arraylist_set_data_collection(struct arraylist *list, value_type* data) {
list->data = data;
}
void arraylist_add(struct arraylist *list, value_type value) {
int size = arraylist_get_size(*list);
value_type *new_data;
new_data = realloc(list->data, (size + 1) * sizeof new_data[0]);
if (new_data)
{
new_data[size] = value;
arraylist_set_data_collection(list, new_data);
++list->size;
}
}
value_type arraylist_get(const struct arraylist list, int index) {
if(index < arraylist_get_size(list)) {
return list.data[index];
}
else {
return NULL;
}
}
int arraylist_indexof(const struct arraylist list, value_type value) {
int index = 0;
for(; index != arraylist_get_size(list); ++index) {
if(strcmp(list.data[index], value) == 0) {
return index;
}
}
return -1;
}
int main(void){
struct arraylist list;
arraylist_initial(&list);
arraylist_add(&list, "1");
arraylist_add(&list, "2");
arraylist_add(&list, "3");
arraylist_add(&list, "4");
arraylist_add(&list, "5");
arraylist_add(&list, "6");
arraylist_add(&list, "7");
arraylist_get_size(list);
int index = 0;
for(; index != 8; ++index) {
printf("CHECK: %s\n", arraylist_get(list, index));
}
return 0;
}
arraylist.h
#define _ARRAYLIST_H
#include <stdio.h>
typedef char* value_type;
struct arraylist {
int size;
value_type* data;
};
extern void arraylist_initial(struct arraylist *list);
extern int arraylist_get_size(const struct arraylist list);
extern value_type* arraylist_get_data_collection(const struct arraylist list);
extern void arraylist_set_data_collection(struct arraylist *list, value_type* data);
extern void arraylist_add(struct arraylist *list, value_type value);
extern value_type arraylist_get(const struct arraylist list, int index);
extern int arraylist_indexof(const struct arraylist list, value_type value);
In arraylist.c if I do
printf(arraylist_get_size_list(list));
It just crash and I dont get it?
thank you
Sorry, I was remembering a time when you couldn't pass structs with C. It looks like you can now. They keep changing things.
Here's the real problem: printf takes a string as the first argument.
Instead of:
printf(arraylist_get_size_list(list));
Try:
printf("size: %d\n", arraylist_get_size_list(list));

Arraylist in C failing on realloc

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);
}

C Queue questions (Exercise)

I just started my first lesson in queues for C, and I was given an exercise to create a queue, adding elements and deleting elements into the queue. However, I am having trouble with checking whether the queue is full or empty.
#include <stdio.h>
typedef struct FloatQueue
{
float data[100];
int rear;
int size;
int front;
} FloatQueue;
typedef enum {false, true} bool;
void initQ (FloatQueue * pq);
bool isFullQ (FloatQueue * pq);
bool isEmptyQ (FloatQueue * pq);
void addQ(FloatQueue * pq, float x);
float deleteQ ( FloatQueue * pq);
int sizeQ (FloatQueue * pq);
void initQ (FloatQueue * pq)
{
pq->size = 0;
pq->front = pq->rear = 0;
}
void main ()
{
FloatQueue q1;
initQ (&q1);
addQ (&q1, 99.9);
addQ (&q1, 888);
while (!isEmptyQ(&q1))
{
printf("%f", deleteQ (&q1));
}
}
int sizeQ (FloatQueue * pq)
{
return pq->size;
}
bool isFullQ (FloatQueue * pq)
{
return true;
}
bool isEmptyQ (FloatQueue * pq)
{
return false;
}
void addQ ( FloatQueue * pq, float x)
{
(pq->rear) ++;
(pq->data[pq->rear]) = x;
(pq->size) ++;
}
float deleteQ ( FloatQueue * pq )
{
(pq->front)++;
return;
}
The queue is full if size == 100 and empty if size == 0. Why is it difficult to check for that?
However, as it is implemented now, it holds that size == 0 if and only if front == rear. That means, you could remove the size from the FloatQueue completely and instead check if front - rear == 0 resp. 100.
BUT: You have to think about one thing: what happens if the rear end exceeds the size? Then you surely have to rearrange something. I leave it to you to find a good solution, which could might mean making use of size again after all (Hint: you don't necessarily have to move data around in the array).
bool isFullQ (FloatQueue * pq)
{
if(pq->size==100)
return true;
}
bool isEmptyQ (FloatQueue * pq)
{
if(pq->front==pq->rear)
return false;
}

Heap error in DLL

I'm looking for some help with some C dll programming. I am getting an error in Visual Studio that occurs when I call free from within the dll. The program runs fine in debug mode within the IDE, but when I try to execute it as "Start without debugging", the program crashes. I read that with debugging, the heap is shared, which probably explains why the code runs fine with F5 and not Ctrl-F5. Is this correct??
I've searched around, and I learned that it is dangerous to pass dynamically allocated memory through the dll-exe boundary, however as I am calling malloc and free from within the same dll, this should not be a problem. I have posted the code below. Any help would be greatly appreciated. Please note that this code works on my Linux box, I am simply trying to port it to Windows to garner experience programming in Windows.
Thank you
#ifndef HASHTABLE_H
#define HASHTABLE_H
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the HASHTABLE_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// HASHTABLE_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef HASHTABLE_EXPORTS
#define HASHTABLE_API __declspec(dllexport)
#else
#define HASHTABLE_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* This is a naive implementation
* of a hashtable
*/
typedef struct node {
struct node *next;
char *value;
char *key;
} Node;
typedef struct hashtable {
struct node **nodes;
int num_elements;
int size;
int (*hash_function)(const char * const);
} Hashtable_str;
// Construction and destruction
HASHTABLE_API void tbl_construct(Hashtable_str **table);
HASHTABLE_API void tbl_destruct(Hashtable_str *table);
// Operations
HASHTABLE_API int tbl_insert (Hashtable_str *table, const char * const key, const char * const element); // return the key
HASHTABLE_API int tbl_remove(Hashtable_str *table, const char * const key);
HASHTABLE_API char * tbl_find(Hashtable_str *table, const char * const key); // return the element
HASHTABLE_API int size(Hashtable_str *table); // Return the size
// default hash function
int def_hash(const char * const key);
#ifdef __cplusplus
}
#endif
#endif
Here is the implementation code
// hashtable.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "hashtable.h"
#include <stdlib.h> // for memcpy
#include <stdio.h>
#include <string.h>
#define SIZE 100
int def_hash(const char * const key)
{
// simply sum the ascii
// values and take modulo
// 100
//int i;
//int sum;
//sum = 0;
//for (i=0; key[i] != '\0'; i++)
// sum += key[i];
//return sum % SIZE;
return 0;
}
// construct a hashtable and return a pointer
HASHTABLE_API void tbl_construct(Hashtable_str **tbl)
{
int i;
Hashtable_str *tbl_ptr;
*tbl = (Hashtable_str*) malloc (sizeof(Hashtable_str*));
tbl_ptr = *tbl;
tbl_ptr->nodes = (Node**) malloc (SIZE * sizeof(Node*));
for (i=0; i < SIZE; i++) tbl_ptr->nodes[i] = NULL;
tbl_ptr->hash_function = &def_hash;
tbl_ptr->num_elements = 0;
tbl_ptr->size = SIZE;
}
HASHTABLE_API void tbl_destruct(Hashtable_str *tbl)
{
void free_tbl_node(Node*); // declare the release function
int i;
for (i=0; i < tbl->size; i++)
{
if (tbl->nodes[i] != NULL)
free_tbl_node(tbl->nodes[i]);
}
}
void free_tbl_node(Node *curr_node)
{
if (curr_node->next != NULL)
free_tbl_node(curr_node->next);
free(curr_node->value);
curr_node->value = NULL;
free(curr_node->key);
curr_node->key = NULL;
//free(curr_node);
//Node *temp = NULL;
//Node *temp2 = NULL;
//temp = temp2 = curr_node;
//while (temp->next != NULL)
//{
// temp2=temp->next;
// free(temp->key);
// free(temp->value);
// free(temp);
// temp=temp2;
//}
}
// table operations
HASHTABLE_API int count(Hashtable_str *tbl) { return tbl->num_elements; }
HASHTABLE_API int size(Hashtable_str *tbl) { return tbl->size; }
HASHTABLE_API int tbl_insert(Hashtable_str *table, const char * const key, const char * const element)
{
int hash;
Node *temp_ptr = NULL;
hash = table->hash_function(key);
// printf("Placing into column %d\n", hash);
if (table->nodes[hash] == NULL)
{
table->nodes[hash] = (Node*) malloc(sizeof(Node*));
temp_ptr = table->nodes[hash];
temp_ptr->next = NULL;
temp_ptr->key = (char*) malloc (strlen(key) + 1 * sizeof(char));
temp_ptr->value = (char*) malloc (strlen(element) + 1 * sizeof(char));
strcpy_s(temp_ptr->key, strlen(key)+1, key);
strcpy_s(temp_ptr->value, strlen(element)+1, element);
table->num_elements += 1;
}
else
{
// Collision!!
temp_ptr = table->nodes[hash];
while (temp_ptr->next != NULL)
temp_ptr = temp_ptr->next;
temp_ptr->next = (Node*) malloc(sizeof(Node));
temp_ptr->next->key = (char*) malloc (strlen(key)+1 * sizeof(char));
temp_ptr->next->value = (char*) malloc (strlen(element)+1 * sizeof(char));
temp_ptr->next->next = NULL;
strcpy_s(temp_ptr->next->key, strlen(key)+1, key);
strcpy_s(temp_ptr->next->value, strlen(element)+1, element);
table->num_elements += 1;
}
// Return the hash value itself for hacking
return hash;
}
HASHTABLE_API int tbl_remove(Hashtable_str *tbl, const char * const key)
{
int hash;
Node *temp_ptr = NULL;
Node *chain = NULL;
hash = tbl->hash_function(key);
if (tbl->nodes[hash] == NULL)
return 1;
else
{
temp_ptr = tbl->nodes[hash];
if (strcmp(key, temp_ptr->key) == 0)
{
// The next node is the node in question
chain = temp_ptr->next;
free(temp_ptr->value);
printf("Deleted the value\n");
free(temp_ptr->key);
printf("Deleted the key\n");
//printf("About to delete the node itself\n");
//free(temp_ptr);
tbl->nodes[hash] = chain;
tbl->num_elements -= 1;
return 0;
}
else
{
while (temp_ptr->next != NULL)
{
if (strcmp(key, temp_ptr->next->key) == 0)
{
// The next node is the node in question
// So grab a pointer to the node after it
// and remove the next node
chain = temp_ptr->next->next;
free(temp_ptr->next->key);
free(temp_ptr->next->value);
//free(temp_ptr->next);
temp_ptr->next = chain;
tbl->num_elements -= 1;
return 0;
}
else
temp_ptr = temp_ptr->next;
}
}
// Couldn't find the node, so declare not existent
return 1;
}
}
HASHTABLE_API char * tbl_find(Hashtable_str *tbl, const char * const key)
{
// Compute the hash for the index
int hash;
Node *temp_ptr = NULL;
hash = tbl->hash_function(key);
if (tbl->nodes[hash] == NULL)
return NULL;
else
{
temp_ptr = tbl->nodes[hash];
if (strcmp(key, temp_ptr->key) != 0)
{
while (temp_ptr->next != NULL)
{
temp_ptr = temp_ptr->next;
if (strcmp(key, temp_ptr->key) == 0)
return temp_ptr->value;
}
}
// Couldn't find the node, so declare not existent
return NULL;
}
}
Here's my main
#include <hashtable.h>
#include <utils.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int i=0;
Hashtable_str *my_table = NULL;
tbl_construct(&my_table);
tbl_insert(my_table, "Daniel", "Student");
tbl_insert(my_table, "Derek", "Lecturer");
//tbl_insert(my_table, "Melvyn", "Lecturer");
tbl_print(my_table);
printf("\nRemoving Daniel...\n");
tbl_remove(my_table, "Daniel");
//tbl_print(my_table);
tbl_destruct(my_table);
my_table = NULL;
scanf_s("%d", &i);
return 0;
}
This is incorrect as allocates the size of a pointer, not a Hashtable_str:
*tbl = (Hashtable_str*) malloc (sizeof(Hashtable_str*));
it should be:
*tbl = malloc(sizeof(Hashtable_str));
Same issue with:
table->nodes[hash] = (Node*) malloc(sizeof(Node*));
See Do I cast the result of malloc?

Resources