How to store table into linked list? - c

So, I've done a little reading and consulted help from a friend. And I think I get it? Actually, my part in the project is just to store the table of characters and frequencies into a linked list. I've written down some codes, so is it possible if anyone can improve it.
Sample Input .txt file (the table of characters and frequencies):
B1
D3
E7
J9
The struct:
struct node {
char info;
int freq;
struct node * next;
struct node * left, *right, *father;
};
typedef struct node * nodeptr;
nodeptr getnode(){
return malloc(sizeof(struct node));
}
The main program (just until the part of storing the table into a linked list):
string input;
nodeptr list = NULL;
FILE *fopen();
int c;
list = fopen("Huffman Table.txt","r");
c = getc(input) ;
while (c!= EOF)
{
putchar(c);
c = getc(input);
}
getch();
fclose(input);
for (node * row = table; row != NULL; row = row->next){
fprintf(file, "%s %i %i", row->info, row->freq);
}
I'm not sure about this part though:
for (node * row = table; row != NULL; row = row->next)
Should I just use this instead?
for(i=0;i<strlen(input);i++){

I don't think
for (node * row = table; row != NULL; row = row->next)
would work because you're suppose to pass in an assignment before the first semicolon.
what you're doing is... i don't really know..
for(i=0;i<strlen(input);i++){
would work better. But i'm not sure, because i don't know what string input is suppose to hold and how you're using row and table

The used for loop is (syntactically) perfectly OK, and isn't that uncommon. However, what's the "table" pointer? Is it root of your list? Small remark - if you created "nodeptr" typedef, you should use it there. That's what it's for. There are some other parts of your code I'm concerned about
You said it was supposed to be a linked list, so why your struct has "father" pointer? It looks more like a tree to me. If it weren't the intent, remove that field.
I am not sure I understood the last piece of code you wrote. If you want to write contents of the list to a file, you should use the for loop mentioned above.
And as of general improvement to this code (which looks like a homework to me, and i guess should be tagged as such), is to use std::list<>. It can however be done only, if you're allowed to code in C++ rather in C.

Related

Removing First element of linked list in C

Seemingly simple C code is seemingly not allowing me to remove the first element from a linked list. I can, however, successfully remove any other individual element and can successfully delete the whole linked list.
typedef struct list{
int data;
struct list * next;
} list;
void remove_element(list * node, unsigned int index){
if (node == NULL)
exit(-1);
list *currElem = node;
if (index == 0) {
node = node->next;
currElem->next = NULL;
free(currElem);
return;
}
Produces the follwing:
"free(): invalid pointer: 0xbfabb964"
I've followed the same format for all of my other manipulation functions with no issues. Similar threads on forums don't seem to be dealing with this particular problem.
You can read the explanation in this pdf on the Push function which explains it:
http://cslibrary.stanford.edu/103/
This is where c gets funky pschologically. You instinctively want to label a pointer as a pointer, which it is. But it is a pointer value, not a pointer reference. It's like the holy spirit of the C divinty. The triumvirate. C passed arguments to functions by value, not by address/reference. So, what do you do to pass a variable by reference? Remember, the solution is so obvious, it really didn't make sense to me for a week, I swear to god.

C - Problems copying string from one struct to a node

I am trying to copy strings from a field in one struct to another struct (a node), so that I can ultimately create a hashtable. However, I seem to be having some issues in the actual string copying. I've created a for loop to iterate over the strings in the source stuct, and I know the iteration is working fine, because if I printf the source strings (data[i].c_name), they print out fine. Unfortunately, when I try to printf the destination (class_id), it seems to be empty (and thus of course my hash function isn't doing much). Any insights into the potential problem here would be greatly appreciated. Please let me know if I haven't given enough context.
#define LENGTH 30
#define MAX_OBS 80000
typedef struct
{
char c_name[LENGTH];
char s_name[LENGTH];
double value[MAX_OBS];
}
sample;
typedef struct node
{
char class_id[LENGTH];
struct node *next;
}
node;
{
char class_id[LENGTH];
for (int i = 0; i < total_columns; i++)
{
// malloc a new node pointer for each new class label
node *new_node = malloc(sizeof(node));
// check that there was sufficient memory
if (new_node == NULL)
{
return 6;
}
// copy c_name into node -- failing - class_id is empty
strcpy(new_node->class_id, data[i].c_name);
printf("%s\n", class_id);
}
}
Drop the last char class_id[LENGTH]; that you print as it was never initialized. Then switch your printf() to use the actual target of the strcpy.
strncpy(new_node->class_id, data[i].c_name, LENGTH);
printf("%.*s\n", LENGTH, new_node->class_id);
I've also put a few LENGTH limits in my code to assure you don't do bad things on bad input without a terminal \0. Never blindly trust your C input unless you generated it in a fail-safe manner.
Disclaimer: desktop inspection changes. Actual debugging is left as an exercise to the student.

Binary Tree Insertion Error

I looked at several BST Insert articles but none of them were structured the same as mine or encountered the same problem.
My problem is my Binary Tree isn't being built correctly. It's really strange because I'm copy+pasting most of the code from a previous project where it works fine, the only difference is the data the nodes contain, and the condition for looping through the tree uses strcmp rather than integer comparison.
This is my insert function:
//insert parameter node data into a Binary Tree
TreeNodePtr insertNode(BinaryTree bst, Record d)
{
//if root is null insert into root
if(bst.root == NULL)
{
bst.root = (TreeNodePtr) malloc(sizeof(TreeNode));
bst.root->data = d;
bst.root->left = NULL;
bst.root->right = NULL;
return bst.root;
}
//we need to traverse the tree so declare a pointer "curr" to do so
TreeNodePtr curr = (TreeNodePtr) malloc(sizeof(TreeNode));
curr = bst.root;
//loop until we find an appropriate empty space or a match (no duplicates)
while (strcmp(d.lastName, curr->data.lastName) != 0)
{
if (strcmp(d.lastName, curr->data.lastName) < 0)
{ // if left
if(curr->left==NULL)
{
curr->left = (TreeNodePtr) malloc(sizeof(TreeNode));
curr->left->data = d;
curr->left->left = NULL;
curr->left->right = NULL;
return bst.root;
}
curr=curr->left;
}
else if (strcmp(d.lastName, curr->data.lastName) > 0)
{ // try right
if(curr->right==NULL)
{
curr->right = (TreeNodePtr) malloc(sizeof(TreeNode));
curr->right->data = d;
curr->right->left = NULL;
curr->right->right = NULL;
return bst.root;
}
curr=curr->right;
}
}
return bst.root;
}
Here is the code in the main function which uses the insert function to build the tree (note that records is a correctly populated array, each index containing one node's data):
//declare BST and build it
BinaryTree phoneTree;
phoneTree.root = NULL;
for (int i=0; i < sizeof(records) / sizeof(Record); i++)
{
Record tmpRecord;
tmpRecord.firstName = records[i].firstName;
tmpRecord.lastName = records[i].lastName;
tmpRecord.phoneNum = records[i].phoneNum;
phoneTree.root = insertNode(phoneTree, tmpRecord);
}
And for reference, here are the tree structs:
//phone data record struct
typedef struct
{
char *firstName;
char *lastName;
char *phoneNum;
}Record;
//define the tree node which contains the data
typedef struct treeNode
{
Record data;
struct treeNode *left,*right;
}TreeNode,*TreeNodePtr;
//define binary tree struct
typedef struct
{
TreeNodePtr root;
}BinaryTree;
I've been staring at the program that works and comparing it to this program for about 5 hours now and I can't figure out what's going wrong. I know the tree isn't populated correctly because if i try to print phoneTree.root->right.data or phoneTree.root->left.data attributes, the program crashes. In the program I'm borrowing the code from, these attributes are printed without error. The root is still inserted correctly and it's attributes can be printed.
Any insight as to what I'm doing incorrectly is greatly appreciated.
There is one definite mistake, which could be causing you problems. You need to pass "bst" by reference, so that the function can modify "bst.root". Try rewriting the function as:
TreeNodePtr insertNode(BinaryTree* bst, Record d)
and use "bst->" in place of "bst."
You said that it worked with integers. Now that may be a clue to another mistake. Your record contains only pointers to strings. Do these pointers remain valid throughout the lifetime of the tree? Maybe you need to make copies of the strings within the record.
Couple of other minor things:
//we need to traverse the tree so declare a pointer "curr" to do so
TreeNodePtr curr = (TreeNodePtr) malloc(sizeof(TreeNode));
curr = bst.root;
malloc is redundant here, the result is immediately overwritten.
And:
}
else if (strcmp(d.lastName, curr->data.lastName) > 0)
{ // try right
you can replace this with "} else {" as you already did this strcmp operation.
Thanks for all the great tips, they've all contributed to my understanding of memory management in C.
Strangely, I found the problem is actually rooted in my array for loop. I found the method of using sizeof(array) / sizeof(arraydatatype) from multiple sources on the internet and this site so I attempted it, but it doesn't work the way I tried. In:
for (int i=0; i < sizeof(records) / sizeof(Record); i++)
{
Record tmpRecord;
tmpRecord.firstName = records[i].firstName;
tmpRecord.lastName = records[i].lastName;
tmpRecord.phoneNum = records[i].phoneNum;
phoneTree.root = insertNode(phoneTree, tmpRecord);
}
I replaced "i < sizeof(records) / sizeof(Record)" with just"i < 3" (array should only have 3 elements at this point), and everything worked as it should. It's a really dumb source of the problem, but funny that despite all the answers provided none mentioned it :p
Since we're already here, can anyone explain why that was going wrong / how to properly loop through an array in such a manner?

Creating Linked List of Locations in C

FIX: I wasn't saving the locations back into world so I was just leaking the information. Credit to Skeeto.
while(!feof(fp)){
loc = readLocation(fp);
join(loc,world);
}
should actually be
while(!feof(fp)){
loc = readLocation(fp);
world = join(loc,world);
}
EDIT: As mentioned in the comments, yes I am a student, but I'm not looking for someone to do my work for me. I'm simply trying to locate possible logic errors because if I could fill this list properly, I can finish my project very easily. This is just a small portion of a very immersive project, helping with this will only allow me to continue the project, not complete it and turn it in. I only provided so much detail because 1) I've never posted here before so didn't know any better, and 2) wanted the reader to understand the workings of this in order to aid them in assisting me. Also, with any concerns as to skype, if that ended up being where successful help was given, I would provide the fix above this 'edit' as well as crediting the stackoverflow user for helping.
TLDR: Yes I'm a student, No im not trying to have someone do my project. This is a very small portion and will only allow me to continue, not complete. If help was given via skype I would update this post with the fix as well as credit the helper.
Hello and thank you for any help in advance.
I am trying to create a linked list that holds objects of type Location *.
I have Location defined as
typedef struct location{
char *name;
char *longer;
char *shorter;
char *north;
char *south;
char *east;
char *west;
char *logic;
int visited;
char *items[20];
} Location;
Furthermore I can succesfully read in all the values for the location and display all attributes so that is not an issue.
In the 'engine' of my game (the main), i attempt to read all the locations into a list as seen in the following (I'm certain readLocation works correctly because I threw a print statement into the loop printing the name of the locations using the loc variable)
world = 0;
FILE *fp = fopen("world.in","r");
char *garb = readToken(fp);
free(garb); //garbage token at begging of world.in just to check file exists
int count = 0; //used later, ignore for now
while(!feof(fp)){
loc = readLocation(fp);
join(loc,world);
}
world is global variable declared as Node * and initialized to 0 (I think i need to do that but am not sure)
In olist.h I create the node structure as
typedef struct node
{
Location *place;
struct node *next;
} Node;
and in olist.c this is how i construct the Node as well as join the nodes
//place is the attribute of the Node that holds the location and next points to the next Node in the list
Node *newNode(Location *loc,Node *next)
{
Node *n = malloc(sizeof(Node));
if (n == 0)
{
fprintf(stderr,"newNode: out of memory!\n");
exit(1);
}
n->place = loc;
n->next = next;
return n;
}
//s is the location i wish to join to the list and rest is list I'm joining to
Node *join(void *s,Node *rest)
{
return newNode(s,rest);
}
Unfortunately, after successfully reading in all locations, world is still an empty list. Thanks for any help and I will be happy to provide further information via this forum or skype: F3V3Rz_MoDz (its a very old name)
If I'm not mistaken, your problem is in the following line of code :
n->next = next;
The head of your linked list is world, but your newNode() function keeps sending world to the back of the list (n->next = next places next at the back). What you want here is to append at the end of your linked list.
Here is an example of code that you can use to do this :
Node *lastNode = next;
while (lastNode->next != NULL)
lastNode = lastNode->next;
lastNode->next = n;
Basically, you iterate through your linked list until you get to the end, then you append the newly created node.
EDIT :
The problem you were having is that the world variable is in the end of your linked list. Every time you call join() you are pushing world at the back of the list. Here's a representation of your list :
Before join() :
world -> null
After join() :
newnode -> world -> null
Therefore, everytime you try to iterate through the list, world does not see the newly created nodes that are before him.
My solution does the following :
world -> newnode -> null
Which basically keeps your world variable in front. So you don't have to do world = join(loc, world)

Swapping 2 Nodes in a Linked List

Good day guys, im new here to C and am trying to learn linked lists. I been trying to swap 2 nodes from within a linked list but so far have been having trouble getting it to work. The code I been trying to use causes an endless circular loop, but I don't think it is because of the if or while statement.
Take a look? Any pointers here? Help would be greatly appreciated.
Basically, the code uses a user input to search for a node based on the data inside, then it should swap the node with the data inside with the next node. Been at this for 3 hours, can anybody help? Thanks!
/conductor is the name im using of the pointer for the current node/
#include <stdio.h>
#include <stdlib.h>
struct node {
int x;
struct node *next;
struct node *prev;
};
struct node *root;
struct node *conductor;
struct node *counter;
struct node *newnode;
struct node *back;
struct node *swapper;
struct node *swappee;
struct node *blanker;
int add = 0;
int initialization = 0;
int query = 0;
int swap ()
{
printf("enter data to search from within the nodes: ");
fflush(stdin);
scanf("%d", &query);
conductor = root;
while ( conductor->next != 0)
{
if(conductor->x == query)
{
printf("\n%d\n", query);
swapper = conductor;
swappee = conductor->prev;
conductor = swappee;
conductor->next = swapper;
break;
}
else
{
conductor = conductor->next;
}
}
mainMenu ();
}
A double linked list (like the one you have) is basically an array of node, each node pointing to its neighbors. Let's say we have nodes -A-B-C-D- (A-B means that A points to B and B points to A). Let's say you want to swap B and C. You have to make 4 changes:
Make A point to C
Make C point to B and A
Make B point to D and B
make D point to B
You make only the second and the third change. So, you need to add A->next = B and D->prev=C. I hope it is clear enough.
Also, you should not fflush input streams.
If you want to swap the data:
if (conductor->x == query) {
int temp = conductor->x;
if (conductor->next)
conductor->x = conductor->next->x;
conductor->next->x = temp;
}
}
Typically that is what you will want to do. If you have a structure with several members instead of the 1 int, swapping the pointers may seem less messy in theory, but it isn't, primarily due to the fact that you must test for existence of a next/previous node so often. In truth, you'd probably want a pointer to a separate structure in such a case.
Given three nodes — previous, current, and next, pointing to current->prev, current, and current->next respectively — you must update at most 6 pointers:
next->prev = previous
previous->next = next
current->prev = next
current->next = next->next
next->next = current
current->next->prev = current
Step 2 is not necessary if previous is NULL.
Step 7 is unnecessary if current->next is NULL.
The entire thing is unnecessary if next is NULL.
If you want to swap with the previous node instead of the next, exchange any instance of the variable previous with the variable next and vice-versa as well as exchanging any instance of ->prev with ->next and vice-versa.
Overall, this requires a fair bit of branching code, which can be slow. This is why it is usually better to swap the data rather than messing with the pointers. It gets even messier when you want to swap with the previous node and you only have a singly-linked list that points to the next node because you must store yet another pointer for the equivalent of previous->prev, assuming previous exists.

Resources