Issue recursively printing nodes from a kd tree via pointers - c

Firstly, forgive me if i do something wrong here since its my first time posting a question.
Can anyone tell me what i am doing incorrectly. When i attempt to iterate through a kd tree and print off all of my points, the 'pnt' attribute to the node i pass in changes its value to a memory address. I am looking at the 'print' and 'printPasser' function (both are located at the bottom). I know i'm doing something wrong with pointers but i just don't know what. If anyone spots something else wrong, please do comment
'''
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char axis;
struct node *left;
struct node *right;
unsigned int val;
struct point *pnt;
//struct point pnt;
} Node;
typedef Node * NodePtr;
typedef struct point
{
unsigned int xVal;
unsigned int yVal;
char *Datum;
} Point;
typedef Point * PointPtr;
typedef struct kdtree
{
struct node *root;
unsigned int xBound;
unsigned int yBound;
} kdTree;
typedef kdTree *kdTreePtr;
//|--------------------------------------------------
kdTreePtr create();
void insert(kdTree * tree, struct point pntInsert);
void insertVal(kdTree * tree, unsigned int xIn, unsigned int yIn, char * Datum);
struct point repeater(struct node * tmp, struct point * pnt);
void delete(kdTree * tree, struct point * pnt);
void destroy(kdTree * tree);
struct point pop(kdTree * tree);
void print(kdTree * tree);
void printPasser(struct node * root);
void insertAlt(kdTree * tree, struct point pntInsert);
void insertPasser(Node * root, struct point pntInsert);
struct point nearestNeighbor(kdTree * tree, struct point * pntInit);
struct point nearestNicestNeighbor(kdTree * tree, struct point * pntInit);
void scale(kdTree * tree, unsigned int xScaler, unsigned int yScaler);
void resize(kdTree * tree, unsigned int xBound, unsigned int yBound);
void analyze(struct node *root);
//|--------------------------------------------------
int main(void)
{
kdTree * basic;
basic = malloc(sizeof(kdTreePtr));
basic = create();
resize(basic, 30, 30);
//Point pntr;
Point pnt1;
Point* pntr1 = &pnt1;
pntr1->xVal = 2;
pntr1->yVal = 7;
pntr1->Datum = "Big";
Point pnt2;
Point* pntr2 = &pnt2;
pntr2->xVal = 3;
pntr2->yVal = 8;
pntr2->Datum = "Bigger";
print(basic);
insertAlt(basic, pnt1);
printf("Point: (%u,%u) main tester\n", basic->root->pnt->xVal, basic->root->pnt->yVal);
print(basic);
insert(basic, pnt2);
print(basic);
return 0;
}
kdTreePtr create()
{
kdTreePtr newTree = malloc(sizeof(kdTree));
newTree->xBound = 0;
newTree->yBound = 0;
newTree->root = malloc(sizeof(NodePtr));
newTree->root->left = NULL;
newTree->root->right = NULL;
newTree->root->pnt = NULL;
return newTree;
}
void resize(kdTree * tree, unsigned int xBound, unsigned int yBound)
{
tree->xBound = xBound;
tree->yBound = yBound;
}
void insertAlt(kdTree * tree, struct point pntInsert)
{
if (tree->root->pnt == NULL && tree->root->left == NULL && tree->root->right == NULL)
{
puts("empty");
//if(tree->root->pnt != NULL)
// printf("Point: (%u,%u) root\n", tree->root->pnt->xVal, tree->root->pnt->yVal);
tree->root->pnt = &pntInsert;
printf("Point: (%u,%u) root end\n", tree->root->pnt->xVal, tree->root->pnt->yVal);
}
else
{
puts("Iterate");
insertPasser(tree->root, pntInsert);
}
}
void insertPasser(Node * root, struct point pntInsert)
{
if (root->pnt == NULL && root->left != NULL && root->right != NULL)
{
if (root->axis == 'y')
{
if (pntInsert.yVal >= root->pnt->yVal)
insertPasser(root->right, pntInsert);
else
insertPasser(root->left, pntInsert);
}
else
{
if (pntInsert.xVal >= root->pnt->xVal)
insertPasser(root->right, pntInsert);
else
insertPasser(root->left, pntInsert);
}
}
else
{
Node *leftChild;
Node *rightChild;
rightChild = malloc(sizeof(NodePtr));
leftChild = malloc(sizeof(NodePtr));
unsigned int lower;
unsigned int xDif,yDif;
if (pntInsert.xVal >= root->pnt->xVal)
{
xDif = abs(pntInsert.xVal - root->pnt->xVal);
lower = root->pnt->xVal;
}
else
{
xDif = abs(root->pnt->xVal - pntInsert.xVal);
lower = pntInsert.xVal;
}
if (pntInsert.yVal >= root->pnt->yVal)
{
yDif = abs(pntInsert.yVal - root->pnt->yVal) ;
lower = root->pnt->yVal;
}
else
{
yDif = abs(root->pnt->yVal - pntInsert.yVal) ;
lower = pntInsert.yVal;
}
if (xDif >= yDif)
{
root->axis = 'y';
root->val = ((unsigned int)xDif / 2) + lower;
if (pntInsert.xVal >= root->pnt->xVal)
{
puts("test 1");
rightChild->pnt = &pntInsert;
leftChild->pnt = root->pnt;
root->right = rightChild;
root->left = leftChild;
root->pnt = NULL;
}
else
{
puts("test 2");
rightChild->pnt = root->pnt;
leftChild->pnt = &pntInsert;
*(root->right) = *rightChild;
*(root->left) = *leftChild;
root->pnt = NULL;
}
}
else
{
root->axis = 'x';
root->val = ((unsigned int)yDif / 2) + lower;
if (pntInsert.yVal >= root->pnt->yVal)
{
puts("test 3");
rightChild->pnt = &pntInsert;
leftChild->pnt = root->pnt;
root->right = rightChild;
root->left = leftChild;
root->pnt = NULL;
}
else
{
puts("test 4");
rightChild->pnt = root->pnt;
leftChild->pnt = &pntInsert;
root->right = rightChild;
root->left = leftChild;
root->pnt = NULL;
}
}
}
}
void insertVal(kdTree * tree, unsigned int xIn, unsigned int yIn, char * Datum)
{
Point pntInsert;
PointPtr pntInsertPtr = &pntInsert;
pntInsert.xVal = xIn;
pntInsert.yVal = yIn;
pntInsert.Datum = Datum;
insertAlt(tree, pntInsert);
//printf("%u,", tree->root->pnt->xVal);
//printf("%u\n", tree->root->pnt->yVal);
//printf("%u,", tree->root->pnt->yVal);
//printf("%u\n", tree->root->pnt->xVal);
}
void print(kdTree * tree)
{
if (tree->root->pnt == NULL && tree->root->left == NULL && tree->root->right == NULL)
puts("blank");
else
{
printf("Point: (%u,%u) \n", tree->root->pnt->xVal, tree->root->pnt->yVal);
printPasser(tree->root);
}
}
void printPasser(struct node * root)
{
printf("Point: (%u,%u) \n", root->pnt->xVal, root->pnt->yVal);
//PointPtr rootHolder =
if (root->left == NULL && root->right == NULL && root->pnt != NULL)
{
printf("Point: (%u,%u) \n", root->pnt->xVal, root->pnt->yVal);
}
else
{
printPasser(root->left);
printPasser(root->right);
}
}
'''
everything looks alright until i pass the node pointer into the 'printPasser' function where i take the point of root and get a new value that just looks to be the pointer values cast to an unsigned int.

I identified the following memory-related issues in your code:
kdTree * basic;
basic = malloc(sizeof(kdTreePtr));
basic = create();
You initialize basic twice. This is not a problem in itself, but it results in a memory leak of size kdTreePtr. Remove the first assignment.
newTree->root = malloc(sizeof(NodePtr));
Whenever you allocate an new Node, you only allocate a pointer-sized chunk of memory, not the size appropriate for a Node. You need to allocated sizeof(Node) bytes. There are multiple occurrences.
After fixing those, your code does not trigger a segmentation fault anymore (when compiling with optimizations enabled) and the output remains stable.

Related

Is there any way to 'reserve' some memory for a struct to make sure other functions can't overwrite it?

For context, I'm a new programmer to C and I wanted to make a toy implementation of a dictionary/map from a 'Person' struct to an integer. I'm using separate chaining, so I have a hash table of linked list pointers.
So far, I've been able to add one value to the linked list just fine, but when I call the function to get the value for the Person key I'm using, the memory at one of my nodes seems to get overwritten.
More info if it's helpful, using a singly linked list with one sentinel node at the head and a tail reference.
New to StackOverflow, so I can't actually embed the image, but pictured on left is the HashTable at the beginning of the function call, when nothing has been changed. The relevant stuff is the expanded part of the Variables menu, which shows that at position 58 is a pointer to 0x61f8e0, the linked list. The linked list has a head pointer to 0x61f760, which is the sentinel value, and a tail pointer to 0x61f864, currently pointing to a Node with the value (3) for a Person named Robert who's 36 years old. The tail pointer's next field points to 0x0 (not pictured), like intended. The picture follows: https://i.stack.imgur.com/F9EJ9.png
This is what happens as soon as the first statement (which hashes the Person pointer very naively) is executed: https://i.stack.imgur.com/UJvGy.png. As you'll see, the value is now some random long number, the intrinsic age is now 1 instead of 36, the saved name is now gibberish, and worst of all the next pointer now points somewhere completely random (0x61fb10).
The function in question follows.
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
Here is the hash function, in case that's what's causing the problems.
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
And just because why not, here's all of the short amount of code I've written for this.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
typedef struct Node {
int val;
int savedAge;
char savedName[100];
struct Node* next;
} Node;
typedef struct {
int age;
char name[100];
} Person;
typedef struct {
Node* head;
Node* tail;
} List;
typedef struct {
List* table[100];
} HashTable;
int hash(Person*);
Person person(int age, char name[]) {
Person p;
p.age = age;
strcpy(p.name, name);
return p;
}
Node node(int val, Person p, Node* next) {
Node n;
n.val = val;
strcpy(n.savedName, p.name);
n.savedAge = p.age;
n.next = next;
return n;
}
List list() {
List l;
Node head = node(-1, person(0, "SENTINEL"), NULL);
l.head = &head;
l.tail = l.head;
return l;
}
void listAdd(List* l, Node n) {
Node* newTailPtr = &n;
l -> tail -> next = newTailPtr;
l -> tail = newTailPtr;
}
HashTable table() {
int table[100] = {0};
HashTable t;
memcpy(t.table, table, sizeof table);
return t;
}
HashTable tableAdd(HashTable t, Person key, int val) {
int num = hash(&key) % 100;
List* loc = t.table[num];
if ((int) loc == 0) {
List newList = list();
t.table[num] = &newList;
}
listAdd((List*) t.table[num], node(val, key, NULL));
return t;
}
int tableGet(HashTable t, Person key) {
int position = hash(&key) % 100;
List* listLoc = t.table[position];
if ((int) listLoc == 0) {
return -1;
}
Node curr = *(listLoc -> head);
while (curr.next != NULL) {
if (curr.savedAge == key.age && curr.savedName == key.name) {
return curr.val;
}
curr = *curr.next;
}
return -1;
}
int hash(Person* p) {
int sum;
Person person = *p;
int i = 0;
char nameChar = person.name[i];
while (nameChar != '\0'){
sum += (int) nameChar;
i += 1;
nameChar = person.name[i];
}
return (int) (person.age + sum);
}
int main() {
Person bob = person(36, "Robert");
printf(bob.name);
printf("\n");
HashTable tab = table();
tab = tableAdd(tab, bob, 3);
printf("Added Robert to table as 3\n");
int val = tableGet(tab, bob);
if (val == 3) {
printf("Success!\n");
} else {
printf("Failure, val is %d\n", val);
}
return 0;
}

How to insert data in linked structure

My insertion worked, so a new question, How do I set a data to NULL in C? Pls see the last part for illustration.!
I have defined a structure type
typedef struct node {
char* data;
int weight;
bool end_of_key;
struct node * left;
struct node * equal;
struct node * right;
} node_t;
int main(int argc, char *argv[]){
node_t* root=NULL;
int weight;
int i = 1;
insert(root,"cat",3);
insert(root,"at",2);
insert(root,"cute",4);
.....
return 0 ;}
This is my insert function
node_t* insert(node_t* pNode,char* word, int weight) {
/**
* Create a new pNode, and save a character from word
*/
pNode = (node_t*)malloc(sizeof(node_t));
if(*pNode->data == NULL){
pNode->left = NULL;
pNode->equal = NULL;
pNode->right = NULL;
pNode->data = word;
}
if (word[0] < *(pNode->data)) {
/**
* Insert the character on the left branch
*/
pNode->left = insert(pNode, word, weight);
}
else if (word[0] == *(pNode->data)) {
if ((word[1]) == '\0') {
/**
*set pNode end_of_key_flag to true and assign weight
*/
pNode->end_of_key = true;
pNode->weight = weight;
// printf("%c", *(pNode->data++));
}
else {
/**
* If the word contains more characters, try to insert them
* under the equal branch
*/
// printf("%c", *(pNode->data++));
pNode->equal = insert(pNode,word + 1, weight);
}
}
else {
/**
* If current char in word is greater than char in pData
* Insert the character on the right branch
*/
pNode->right = insert(pNode,word, weight);
}
return pNode;}
this code is trying to do this
So my insertion finally worked but it appears that it can only insert one thing,I am wondering how do I set data to NULL in C?
if(*pNode->data == NULL){
pNode->left = NULL;
pNode->equal = NULL;
pNode->right = NULL;
pNode->data = word;
}
I want to run this four lines of code when *pNode->data is empty but it apparently did not work the way I wanted it to.
Some improvements of your code
insert() must have first parameter to be node_t ** (see comments)
char *data must be char data, because every node contains only one char
weight can be calculated when the list is filled up
Here is corrected version of your code. Function get() is used to find the key in the filled up list (for testing).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
char data;
int weight;
struct node * left;
struct node * equal;
struct node * right;
} node_t;
void insert(node_t** pNode, char* word, int weight)
{
char data;
node_t **pNext;
node_t *pCurrent;
if (word == NULL)
{
return ;
}
data = word[weight];
if (*pNode == NULL)
{
*pNode = malloc(sizeof(node_t));
pCurrent = *pNode;
memset(pCurrent, 0, sizeof(node_t));
pCurrent->data = data;
}
else
{
pCurrent = *pNode;
}
if (data == pCurrent->data)
{
weight ++;
if (strlen(word) == weight)
{
pCurrent->weight = weight;
return;
}
pNext = &pCurrent->equal;
}
else if (data > pCurrent->data)
{
pNext = &pCurrent->right;
}
else
{
pNext = &pCurrent->left;
}
insert(pNext, word, weight);
}
int get(node_t** pNode, char *word, int weight)
{
char data;
node_t **pNext;
node_t *pCurrent;
if (word == NULL)
{
return 0;
}
data = word[weight];
if (*pNode == NULL)
{
return 0; // not found
}
pCurrent = *pNode;
if (data == pCurrent->data)
{
weight ++;
if (strlen(word) == weight)
{
return pCurrent->weight;
}
pNext = &pCurrent->equal;
}
else if (data > pCurrent->data)
{
pNext = &pCurrent->right;
}
else
{
pNext = &pCurrent->left;
}
return get(pNext, word, weight);
}
int main()
{
node_t * root = NULL;
insert(&root, "cat", 0);
insert(&root, "at", 0);
insert(&root, "cute", 0);
printf("cat=%d\n",get(&root,"cat",0)); // cat=3
printf("at=%d\n",get(&root,"at",0)); // at=2
printf("cute=%d\n",get(&root,"cute",0)); // cute=4
// todo: free memory
return 0;
}
The code is tested except freeing the memory.
First, there is something wrong with your insert() signature
(as already pointed by #MichaelWalz )
you'd rather
node_t* insert(node_t** pNode, char* word, int weight);
and then
insert(&root,"cute",4);
why don't you start fixing this and edit your post ?

SegFault when passing functions in C

I'm getting a SegFault when passing a function pointer through a couple of structs and I can't figure out what I'm doing wrong. Here's the code:
typedef int (*CompareFuncT)( void *, void * );
typedef void (*DestructFuncT)( void * );
struct AVL
{
void * obj;
struct AVL * parent;
struct AVL * leftChild;
struct AVL * rightChild;
};
typedef struct AVL * AVLPtr;
struct SortedList
{
AVLPtr root;
CompareFuncT comp;
DestructFuncT dest;
};
typedef struct SortedList * SortedListPtr;
SortedListPtr SLCreate(CompareFuncT cf, DestructFuncT df){
SortedListPtr slp = malloc(sizeof(struct SortedList));
if(slp == NULL){
printf("Not enough space for list\n");
return NULL;
}
slp->root = NULL;
slp->comp = cf;
slp->dest = df;
return slp;
}
AVLPtr avl_insert(AVLPtr root, AVLPtr parent, void * obj, int (*compare)( void *, void * )){
int s = 5;
int k = 6;
compare(&s, &k);
if(root == NULL){
root = malloc(sizeof(struct AVL));
if(root == NULL){
printf ("Out of memory - creating AVL node\n");
return NULL;
}
root->obj = obj;
root->parent = parent;
root->leftChild = NULL;
root->rightChild = NULL;
return root;
}
else if (compare(obj, root->obj) < 0){
root->leftChild = avl_insert(root->leftChild, root, obj, compare);
root = balance(root);
}
else if (compare(obj, root->obj) >= 0){
root->rightChild = avl_insert(root->rightChild, root, obj, compare);
root = balance(root);
}
return root;
}
int SLInsert(SortedListPtr list, void * newObj){
list->root = avl_insert(list->root, newObj, list->comp);
if(list->root == NULL)
return 0;
return 1;
}
int compareInts(void *p1, void *p2)
{
int i1 = *(int*)p1;
int i2 = *(int*)p2;
return i1 - i2;
}
void destroyBasicTypeNoAlloc(void *p) {
return;
}
int main(int argc, char **argv) {
int s = 9;
SortedListPtr list = SLCreate(compareInts, destroyBasicTypeNoAlloc);
SLInsert(list, &s);
return 0;
}
There's obviously more parameters going through the function, but this is the propagation of my compare function. I'm getting a SegFault on the compare in avl_insert. I have a feeling I'm just not passing a pointer where I should be, but I just can't find it.
The error is your call of malloc:
SortedListPtr slp = malloc(sizeof(SortedListPtr));
You are allocating the number of bytes that a pointer takes up, which is incorrect. It should be:
SortedListPtr slp = malloc(sizeof(struct SortedList));

Doubly linked list: Incompatible pointer types

at the moment I'm working on an implementation of a balanced B-Tree in C. I decided to use doubly linked lists but I have run into some problems. At the moment I get warnings for line 94, 95 and 96 because apparently the pointer types are incompatible.
I really don't see how and any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int data1;
int data2;
int data2exists; // no: 0 , yes: 1
struct node * parent;
struct node * left;
struct node * middle;
struct node * right;
} node;
node * insert(int *, node *, node *);
void getInput(int *);
node * createNode(int *);
void quickSwap(node *, int *, int *, int *, int *);
node * splitLeaf(int *, int *, int *, node *, node *);
void printTree(node *);
void main() {
int input;
getInput(&input);
node * root = createNode(&input);
getInput(&input);
insert(&input, root, root); // returns current pos
getInput(&input);
insert(&input, root, root); // returns current pos
getInput(&input);
insert(&input, root, root); // returns current pos
printTree(root);
}
node * insert(int * input, node * root, node * currentPos) {
printf("data1: [%i], data2: [%i], d2exists: [%i], input: [%i]\n", currentPos->data1, currentPos->data2, currentPos->data2exists, *input);
if (currentPos->left == NULL && currentPos->middle == NULL && currentPos->right == NULL) {
// no children
if (*input > currentPos->data1 && currentPos->data2exists == 0) {
// data1 < input, no data2
currentPos->data2 = *input;
currentPos->data2exists = 1;
return(currentPos);
// printf("CASE1: data1 < input, no data2, no children\n");
}
if (*input < currentPos->data1 && currentPos->data2exists == 0) {
// data1 > input, no data2
currentPos->data2 = currentPos->data1;
currentPos->data1 = *input;
currentPos->data2exists = 1;
return(currentPos);
// printf("CASE2: data1 > input, no data2, no children\n");
}
if (currentPos->data2exists == 1) {
// data2 exists
int smallest;
int middle;
int largest;
quickSwap(currentPos, input, &smallest, &middle, &largest);
printf("s: [%i] m: [%i] l: [%i]\n", smallest, middle, largest);
root = splitLeaf(&smallest, &middle, &largest, currentPos, root);
}
}
return(currentPos);
}
void printTree(node * root) {
if (root->parent != NULL) {
printf("printTree() did not receive root!!!!\n");
return;
}
else {
printf("%i || %i", root->data1, root->data2);
printf("\n");
// printf("%i || %i", root->left->data1, root->left->data2);
// printf("\t\t");
// printf("%i || %i", root->middle->data1, root->middle->data2);
// printf("\t\t");
// printf("%i || %i", root->right->data1, root->right->data2);
// printf("\n");
}
}
node * splitLeaf(int * smallest, int * middle, int * largest, node * currentPos, node * root) {
// this function needs to return root!
if (currentPos->parent == NULL) {
// currentPos is root
// create a parent with median
node * root = createNode(middle);
node * left = createNode(smallest);
node * middle = createNode(largest);
// genau hier gehts weiter! hier müssen root, left und, middle verknüpft werden!
root->left = left;
root->middle = middle;
left->parent = middle->parent = root;
// printf("root-addr: %i, left->parent: %i\n", root, left->parent);
return(root);
}
}
void quickSwap(node * currentPos, int * input, int * smallest, int * middle, int * largest) {
// writes values to *smallest, *middle and *largest ordered by size
if (currentPos->data1 > currentPos->data2) {
*smallest = currentPos->data2;
*middle = currentPos->data1;
}
else {
*smallest = currentPos->data1;
*middle = currentPos->data2;
}
if (*input < *smallest) {
*largest = *middle;
*middle = *smallest;
*smallest = *input;
}
else if (*input < *middle) {
*largest = *middle;
*middle = *input;
}
else {
*largest = *input;
}
}
node * createNode(int * input) {
node * ptr = (node*) malloc(sizeof(node));
ptr->data1 = * input;
ptr->data2 = 0;
ptr->data2exists = 0;
ptr->parent = NULL;
ptr->left = NULL;
ptr->middle = NULL;
ptr->right = NULL;
return(ptr);
}
void getInput(int * input) {
printf("Enter a number\n");
scanf(" %i",input);
}
Aha! The problem is a tricky one. It has to do with the definition of your node struct. The members parent, left, middle and right are of type struct node but you typedefed the struct to be node directly. My guess is that GCC ignores the undefined struct node and hopes it's defined somewhere else.
In other words: the type node exists, but struct node doesn't. Therefore when you try to assign a node to a struct node GCC doesn't know what to do. So change
typedef struct {
...
} node;
to
typedef struct node {
...
} node;
Although it might be wiser to use another name for the struct node than the type node.
Some nitpicks:
GCC complains that main doesn't return an int (just return 0;)
In splitLeaf you're redeclaring the arguments int * middle to node * middle and the same with root.
splitLeaf doesn't return anything when currentPos->parent isn't NULL (though maybe you haven't finished the function yet)

Is it possible to have a linked list of different data types?

This is just another interview question.
Can we have a linked list of different data types, i.e. each element in a linked list can have different structure or union elements? If it's possible can you please explain with an example?
Well in a linked list you don't HAVE to link like for like structs together. As long as they have the appropriate forward and/or backwards pointers you are fine. For example:
struct BaseLink
{
BaseLink* pNext;
BaseLink* pPrev;
int typeId;
};
struct StringLink
{
BaseLink baseLink;
char* pString;
};
struct IntLink
{
BaseLink baseLink;
int nInt;
};
This way you'd have a linked list that goes from BaseLink to BaseLink. The extra data is not a problem. You want to see it as a StringLink? Then cast the BaseLink to a StringLink.
Just remember that you need some form of typeid in there so you know what to cast it to when you arrive at it.
Use union to create the datatype
union u_tag{
char ch;
int d;
double dl;
};
struct node {
char type;
union u_tag u;
struct node *next;
};
Use struct node to create linked list. type decides what is the datatype of the data.
Harsha T, Bangalore
You can use a union type:
enum type_tag {INT_TYPE, DOUBLE_TYPE, STRING_TYPE, R1_TYPE, R2_TYPE, ...};
struct node {
union {
int ival;
double dval;
char *sval;
struct recordType1 r1val;
struct recordType2 r2val;
...
} data;
enum type_tag dataType;
struct node *prev;
struct node *next;
};
Another method I've explored is to use a void* for the data and attach pointers to functions that handle the type-aware stuff:
/**
* Define a key type for indexing and searching
*/
typedef ... key_t;
/**
* Define the list node type
*/
struct node {
void *data;
struct node *prev;
struct node *next;
void *(*cpy)(void *); // make a deep copy of the data
void (*del)(void *); // delete the data
char *(*dpy)(void *); // format the data for display as a string
int (*match)(void *, key_t); // match against a key value
};
/**
* Define functions for handling a specific data type
*/
void *copyARecordType(void *data)
{
struct aRecordType v = *(struct aRecordType *) data;
struct aRecordType *new = malloc(sizeof *new);
if (new)
{
// copy elements of v to new
}
return new;
}
void deleteARecordType(void *data) {...}
char *displayARecordType(void *data) {...}
int matchARecordType(void *data, key_t key) {...}
/**
* Define functions for handling a different type
*/
void *copyADifferentRecordType(void *data) {...}
void deleteADifferentRecordType(void *data) {...}
char *displayADifferentRecordType(void *data) {...}
int matchADifferentRecordType(void *data, key_t key) {...}
/**
* Function for creating new list nodes
*/
struct node *createNode(void *data, void *(*cpy)(void *), void (*del)(void *),
char *(*dpy)(void *), int (*match)(void *, key_t))
{
struct node *new = malloc(sizeof *new);
if (new)
{
new->cpy = cpy;
new->del = del;
new->dpy = dpy;
new->match = match;
new->data = new->cpy(data);
new->prev = new->next = NULL;
}
return new;
}
/**
* Function for deleting list nodes
*/
void deleteNode(struct node *p)
{
if (p)
p->del(p->data);
free(p);
}
/**
* Add new node to the list; for this example, we just add to the end
* as in a FIFO queue.
*/
void addNode(struct node *head, void *data, void *(*cpy)(void*),
void (*del)(void *), char *(*dpy)(void *), int (*match)(void*, key_t))
{
struct node *new = createNode(data, cpy, del, dpy, match);
if (!head->next)
head->next = new;
else
{
struct node *cur = head->next;
while (cur->next != NULL)
cur = cur->next;
cur->next = new;
new->prev = cur;
}
}
/**
* Examples of how all of this would be used.
*/
int main(void)
{
struct aRecordType r1 = {...};
struct aDifferentRecordType r2 = {...};
struct node list, *p;
addNode(&list, &r1, copyARecordType, deleteARecordType, displayARecordType,
matchARecordType);
addNode(&list, &r2, copyADifferentRecordType, deleteADifferentRecordType,
displayADifferentRecordType, matchADifferentRecordType);
p = list.next;
while (p)
{
printf("Data at node %p: %s\n", (void*) p, p->dpy(p->data));
p = p->next;
}
return 0;
}
Obviously, I've left out some error checking and handling code from this example, and I don't doubt there are a host of problems with it, but it should be illustrative.
You can have each node in a linked list have a void* that points to your data. It's up to you how you determine what type of data that pointer is pointing to.
If you don't want to have to specify the type of every node in the list via the union solution you can always just store the data in a char* and take type-specific function pointers as parameters to type-sensitive operations such as printing or sorting the list.
This way you don't have to worry about what node is what type and can just cast the data however you like.
/* data types */
typedef struct list_node list_node;
struct list_node {
char *data;
list_node *next;
list_node *prev;
};
typedef struct list list;
struct list {
list_node *head;
list_node *tail;
size_t size;
};
/* type sensitive functions */
int list_sort(list *l, int (*compar)(const void*, const void*));
int list_print(list *l, void (*print)(char *data));
Yes, I do this by defining the list's element's value as a void pointer void*.
In order to know the type stored in each element of the list I also have a .type field in there, so I know how to dereference what the pointer is pointing to for each element.
struct node {
struct node* next;
int type;
void* value;
};
Here's a full example of this:
//
// An exercise to play with a struct that stores anything using a void* field.
//
#include <stdio.h>
#define TRUE 1
int TYPE_INT = 0;
int TYPE_STRING = 1;
int TYPE_BOOLEAN = 2;
int TYPE_PERSON = 3;
struct node {
struct node* next;
int type;
void* value;
};
struct person {
char* name;
int age;
};
int main(int args, char **argv) {
struct person aPerson;
aPerson.name = "Angel";
aPerson.age = 35;
// Define a linked list of objects.
// We use that .type field to know what we're dealing
// with on every iteration. On .value we store our values.
struct node nodes[] = {
{ .next = &nodes[1], .type = TYPE_INT , .value=1 },
{ .next = &nodes[2], .type = TYPE_STRING , .value="anyfing, anyfing!" },
{ .next = &nodes[3], .type = TYPE_PERSON , .value=&aPerson },
{ .next = NULL , .type = TYPE_BOOLEAN, .value=TRUE }
};
// We iterate through the list
for ( struct node *currentNode = &nodes[0]; currentNode; currentNode = currentNode->next) {
int currentType = (*currentNode).type;
if (currentType == TYPE_INT) {
printf("%s: %d\n", "- INTEGER", (*currentNode).value); // just playing with syntax, same as currentNode->value
} else if (currentType == TYPE_STRING) {
printf("%s: %s\n", "- STRING", currentNode->value);
} else if (currentType == TYPE_BOOLEAN) {
printf("%s: %d\n", "- BOOLEAN (true:1, false:0)", currentNode->value);
} else if (currentType == TYPE_PERSON) {
// since we're using void*, we end up with a pointer to struct person, which we *dereference
// into a struct in the stack.
struct person currentPerson = *(struct person*) currentNode->value;
printf("%s: %s (%d)\n","- TYPE_PERSON", currentPerson.name, currentPerson.age);
}
}
return 0;
}
Expected output:
- INTEGER: 1
- STRING: anyfing, anyfing!
- TYPE_PERSON: Angel (35)
- BOOLEAN (true:1, false:0): 1
As said, you can have a node this questionwith a void*. I suggest using something to know about your type :
typedef struct
{
/* linked list stuff here */
char m_type;
void* m_data;
}
Node;
See this question.
Actually, you don't have to put the pointer first in the structure, you can put it anywhere and then find the beginning fo the struct with a containerof() macro. The linux kernel does this with its linked lists.
http://isis.poly.edu/kulesh/stuff/src/klist/
I use these macros I wrote to make general linked lists. You just create your own struct and use the macro list_link somewhere as a member of the struct. Give that macro one argument naming the struct (without the struct keyword). This implements a doubly linked list without a dummy node (e.g. last node links back around to first node). The anchor is a pointer to the first node which starts out initialized by list_init(anchor) by giving it the lvalue (a dereferenced pointer to it is an lvalue). Then you can use the other macros in the header. Read the source for comments about each available macro functions. This is implemented 100% in macros.
http://phil.ipal.org/pre-release/list-0.0.5.tar.bz2
Yes,Sure You can insert any data type values in the linked list I've designed and its very simple to do so.I have used different constructors of node and boolean variables to check that which type value is inserted and then I do operation and command according to that value in my program.
//IMPLEMENTATION OF SINGLY LINKED LISTS
#include"iostream"
#include"conio.h"
#include <typeinfo>
using namespace std;
class node //struct
{
public:
node* nextptr;
int data;
////////////////////////////////just to asure that user can insert any data type value in the linked list
string ss;
char cc;
double dd;
bool stringTrue=0;
bool intTrue = 0;
bool charTrue = 0;
bool doubleTrue = 0;
////////////////////////////////just to asure that user can insert any data type value in the linked list
node()
{
nextptr = NULL;
}
node(int d)
{
data = d;
nextptr = NULL;
intTrue = 1;
}
////////////////////////////////just to asure that user can insert any data type value in the linked list
node(string s)
{
stringTrue = 1;
ss = s;
nextptr = NULL;
}
node(char c)
{
charTrue = 1;
cc = c;
nextptr = NULL;
}
node(double d)
{
doubleTrue = 1;
dd = d;
nextptr = NULL;
}
////////////////////////////////just to asure that user can insert any data type value in the linked list
//TO Get the data
int getintData()
{
return data;
}
string getstringData()
{
return ss;
}
double getdoubleData()
{
return dd;
}
char getcharData()
{
return cc;
}
//TO Set the data
void setintData(int d)
{
data = d;
}
void setstringData(string s)
{
ss = s;
}
void setdoubleData(double d)
{
dd = d;
}
void setcharData(char c)
{
cc = c;
}
char checkWhichInput()
{
if (intTrue == 1)
{
return 'i';
}
else if (stringTrue == 1)
{
return 's';
}
else if (doubleTrue == 1)
{
return 'd';
}
else if (charTrue == 1)
{
return 'c';
}
}
//////////////////////////////Just for the sake of implementing for any data type//////////////////////////////
node* getNextptr()
{
return nextptr;
}
void setnextptr(node* nptr)
{
nextptr = nptr;
}
};
class linkedlist
{
node* headptr;
node* addnodeatspecificpoition;
public:
linkedlist()
{
headptr = NULL;
}
void insertionAtTail(node* n)
{
if (headptr == NULL)
{
headptr = n;
}
else
{
node* rptr = headptr;
while (rptr->getNextptr() != NULL)
{
rptr = rptr->getNextptr();
}
rptr->setnextptr(n);
}
}
void insertionAtHead(node *n)
{
node* tmp = n;
tmp->setnextptr(headptr);
headptr = tmp;
}
int sizeOfLinkedList()
{
int i = 1;
node* ptr = headptr;
while (ptr->getNextptr() != NULL)
{
++i;
ptr = ptr->getNextptr();
}
return i;
}
bool isListEmpty() {
if (sizeOfLinkedList() <= 1)
{
return true;
}
else
{
false;
}
}
void insertionAtAnyPoint(node* n, int position)
{
if (position > sizeOfLinkedList() || position < 1) {
cout << "\n\nInvalid insertion at index :" << position;
cout <<".There is no index " << position << " in the linked list.ERROR.\n\n";
return;
}
addnodeatspecificpoition = new node;
addnodeatspecificpoition = n;
addnodeatspecificpoition->setnextptr(NULL);
if (headptr == NULL)
{
headptr = addnodeatspecificpoition;
}
else if (position == 0)
{
addnodeatspecificpoition->setnextptr(headptr);
headptr = addnodeatspecificpoition;
}
else
{
node* current = headptr;
int i = 1;
for (i = 1; current != NULL; i++)
{
if (i == position)
{
addnodeatspecificpoition->setnextptr(current->getNextptr());
current->setnextptr(addnodeatspecificpoition);
break;
}
current = current->getNextptr();
}
}
}
friend ostream& operator<<(ostream& output,const linkedlist& L)
{
char checkWhatInput;
int i = 1;
node* ptr = L.headptr;
while (ptr->getNextptr() != NULL)
{
++i;
checkWhatInput = ptr->checkWhichInput();
/// <summary>
switch (checkWhatInput)
{
case 'i':output <<ptr->getintData()<<endl;
break;
case 's':output << ptr->getstringData()<<endl;
break;
case 'd':output << ptr->getdoubleData() << endl;
break;
case 'c':output << ptr->getcharData() << endl;
break;
default:
break;
}
/// </summary>
/// <param name="output"></param>
/// <param name="L"></param>
/// <returns></returns>
ptr = ptr->getNextptr();
}
/// <summary>
switch (checkWhatInput)
{
case 'i':output << ptr->getintData() << endl;
break;
case 's':output << ptr->getstringData() << endl;
break;
case 'd':output << ptr->getdoubleData() << endl;
break;
case 'c':output << ptr->getcharData() << endl;
break;
default:
break;
}
/// </summary>
/// <param name="output"></param>
/// <param name="L"></param>
/// <returns></returns>
if (ptr->getNextptr() == NULL)
{
output << "\nNULL (There is no pointer left)\n";
}
return output;
}
~linkedlist() {
delete addnodeatspecificpoition;
}
};
int main()
{
linkedlist L1;
//Insertion at tail
L1.insertionAtTail(new node("dsaf"));
L1.insertionAtTail(new node("sadf"));
L1.insertionAtTail(new node("sfa"));
L1.insertionAtTail(new node(12));
L1.insertionAtTail(new node(67));
L1.insertionAtTail(new node(23));
L1.insertionAtTail(new node(45.677));
L1.insertionAtTail(new node(12.43556));
//Inserting a node at head
L1.insertionAtHead(new node(1));
//Inserting a node at any given point
L1.insertionAtAnyPoint(new node(999), 3);
cout << L1;
cout << "\nThe size of linked list after insertion of elements is : " << L1.sizeOfLinkedList();
}
The output is
1
dsaf
sadf
999
sfa
12
67
23
45.677
12.4356
Thats what you can use to create a linked list without worrying of data type
Just an FYI, In C# you can use Object as your data member.
class Node
{
Node next;
Object Data;
}
User can then use something like this to find out which Object the Node stores:
if (obj.GetType() == this.GetType()) //
{
}

Resources