I am creating a linked list as in the previous question I asked. I have found that the best way to develop the linked list is to have the head and tail in another structure. My products struct will be nested inside this structure. And I should be passing the list to the function for adding and deleting. I find this concept confusing.
I have implemented the initialize, add, and clean_up. However, I am not sure that I have done that correctly.
When I add a product to the list I declare some memory using calloc. But I am thinking shouldn't I be declaring the memory for the product instead. I am really confused about this adding.
Many thanks for any suggestions,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 128
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct product_data_t *next;
}product_data_t;
typedef struct list
{
product_data_t *head;
product_data_t *tail;
}list_t;
void add(list_t *list, int code, char name[], int cost);
void initialize(list_t *list);
void clean_up(list_t *list);
int main(void)
{
list_t *list = NULL;
initialize(list);
add(list, 10, "Dell Inspiron", 1500);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
// Allocate memory for the new product
list = calloc(1, sizeof(list_t));
if(!list)
{
fprintf(stderr, "Cannot allocated memory");
exit(1);
}
if(list)
{
// First item to add to the list
list->head->product_code = code;
list->head->product_cost = cost;
strncpy(list->head->product_name, name, sizeof(list->head->product_name));
// Terminate the string
list->head->product_name[127] = '/0';
}
}
// Initialize linked list
void initialize(list_t *list)
{
// Set list node to null
list = NULL;
list = NULL;
}
// Release all resources
void clean_up(list_t *list)
{
list_t *temp = NULL;
while(list)
{
temp = list->head;
list->head = list->head->next;
free(temp);
}
list = NULL;
list = NULL;
temp = NULL;
}
============================== Edited ============================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PRODUCT_NAME_LEN 64
// typedef struct product_data product_data_t;
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
}product_data_t;
typedef struct list
{
struct list *head;
struct list *tail;
struct list *next;
struct list *current_node;
product_data_t *data;
}list_t;
void add(list_t *list, int code, char name[], int cost);
int main(void)
{
list_t *list = NULL;
list = initialize(list);
add(list, 1001, "Dell Inspiron 2.66", 1299);
add(list, 1002, "Macbook Pro 2.66", 1499);
clean_up(list);
getchar();
return 0;
}
void add(list_t *list, int code, char name[], int cost)
{
/* Allocate memory for the new product */
product_data_t *product = (product_data_t*) calloc(1, sizeof(*product));
if(!product)
{
fprintf(stderr, "Cannot allocate memory.");
exit(1);
}
/* This is the first item in the list */
product->product_code = code;
product->product_cost = cost;
strncpy(product->product_name, name, sizeof(product->product_name));
product->product_name[PRODUCT_NAME_LEN - 1] = '\0';
if(!list->head)
{
/* Assign the address of the product. */
list = (list_t*) product;
/* Set the head and tail to this product */
list->head = (list_t*) product;
list->tail = (list_t*) product;
}
else
{
/* Append to the tail of the list. */
list->tail->next = (list_t*) product;
list->tail = (list_t*) product;
}
/* Assign the address of the product to the data on the list. */
list->data = (list_t*) product;
}
If you are looking to better understand the basics of linked lists, take a look at the following document:
http://cslibrary.stanford.edu/103/LinkedListBasics.pdf
Arguably you want your list data structure to be external to the data that it stores.
Say you have:
struct Whatever
{
int x_;
}
Then your list structure would look like this:
struct Whatever_Node
{
Whatever_Node* next_
Whatever* data_
}
Ryan Oberoi commented similarly, but w/o example.
In your case the head and tail could simply point to the beginning and end of a linked-list. With a singly linked-list, only the head is really needed. At it's most basic, a linked-list can be made by using just a struct like:
typedef struct listnode
{
//some data
struct listnode *next;
}listnodeT;
listnodeT *list;
listnodeT *current_node;
list = (listnodeT*)malloc(sizeof(listnodeT));
current_node = list;
and as long as list is always pointing to the beginning of the list and the last item has next set to NULL, you're fine and can use current_node to traverse the list. But sometimes to make traversing the list easier and to store any other data about the list, a head and tail token are used, and wrapped into their own structure, like you have done. So then your add and initialize functions would be something like (minus error detection)
// Initialize linked list
void initialize(list_t *list)
{
list->head = NULL;
list->tail = NULL;
}
void add(list_t *list, int code, char name[], int cost)
{
// set up the new node
product_data_t *node = (product_data_t*)malloc(sizeof(product_data_t));
node->code = code;
node->cost = cost;
strncpy(node->product_name, name, sizeof(node->product_name));
node->next = NULL;
if(list->head == NULL){ // if this is the first node, gotta point head to it
list->head = node;
list->tail = node; // for the first node, head and tail point to the same node
}else{
tail->next = node; // append the node
tail = node; // point the tail at the end
}
}
In this case, since it's a singly linked-list, the tail is only really useful for appending items to the list. To insert an item, you'll have to traverse the list starting at the head. Where the tail really comes in handy is with a doubly-linked list, it allows you to traverse the list starting at either end. You can traverse this list like
// return a pointer to element with product code
product_data_t* seek(list_t *list, int code){
product_data_t* iter = list->head;
while(iter != NULL)
if(iter->code == code)
return iter;
iter = iter->next;
}
return NULL; // element with code doesn't exist
}
Often times, the head and tail are fully constructed nodes themselves used as a sentinel to denote the beginning and end of a list. They don't store data themselves (well rather, their data represent a sentinel token), they are just place holders for the front and back. This can make it easier to code some algorithms dealing with linked lists at the expense of having to have two extra elements. Overall, linked lists are flexible data structures with several ways to implement them.
oh yeah, and nik is right, playing with linked-lists are a great way to get good with pointers and indirection. And they are also a great way to practice recursion too! After you have gotten good with linked-list, try building a tree next and use recursion to walk the tree.
I am not writing the code here but you need to do the following:
Create and object of list, this will remain global for the length of program.
Malloc the size of product _ data _ t.
For first element (head is NULL), point head to the malloced' address.
To add next element, move to the end of list and then add the pointer of malloced address to next of last element. (The next of the last element will always be NULL, so thats how you traverse to end.)
Forget tail for a while.
If you are learning C pointer theory this is a good exercise.
Otherwise, it feels like too much indirection for code that is not generic (as in a library).
Instead of allocating a static 128 byte character string, you might want to do some more pointer practice and use an allocated exact length string that you clean up at exit.
Academically, kungfucraigs' structure looks more generic then the one you have defined.
You're calloc'ing space for your list_t struct, just pointers to list head and tail, which isn't what you want to do.
When you add to a linked list, allocate space for an actual node in the list, which is your product_data_t struct.
You're allocating the wrong chunk of memory. Instead of allocating memory for each list element, you're allocating for the list head and tail.
For simplicity, get rid of the separate structure for the head and tail. Make them global variables (the same scope they're in now) and change them to be listhead and listtail. This will make the code much more readable (you won't be needlessly going through a separate structure) and you won't make the mistake of allocating for the wrong struct.
You don't need a tail pointer unless you're going to make a doubly linked list. Its not a major element to add once you create a linked list, but not necessary either.
In memory your items are linked by pointers in the list structure
item1 -> item2
Why not make the list structure part of your item?
Then you allocate a product item, and the list structure is within it.
typedef struct product_data
{
int product_code;
char product_name[PRODUCT_NAME_LEN];
int product_cost;
struct list_t list; // contains the pointers to other product data in the list
}product_data_t;
I think u first need to Imagin back-end. Code are nothing to important. Go here and visualize back-end basic c code of all insertion.
1) Insertion at beginning Visit and scroll to get every instruction execution on back- end
And u need front and imagin Go here
Back end imagin
And All other possible insertion here.
And important thing u can use this way.
struct Node{
int data;//data field
struct Node*next;//pointer field
};
struct Node*head,*tail; // try this way
or short cut
struct Node{
int data;//data field
struct Node*next;//pointer field
}*head,*tail; //global root pointer
And << Click >> To visualize other linked list problem.
Thanks.
A demo for Singly Linked List. If you prefer, try to check Circular Linked List and Doubly Linked List.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node * next;
} node_t;
// Iterating over a list
void
print_list(node_t *head)
{
node_t *current = head;
while(current != NULL)
{
printf("%d\n", current->val);
current = current->next;
}
}
// Adding an item to the end of the list
void
push_end(node_t *head, int val)
{
node_t *current = head;
while (current->next != NULL)
{
current = current->next;
}
current->next = malloc(sizeof(node_t));
current->next->val = val;
current->next->next = NULL;
}
// Adding an item to the head of the list
void
push_head(node_t **head, int val)
{
node_t *new_node = NULL;
new_node = malloc(sizeof(node_t));
new_node->val = val;
new_node->next = *head;
*head = new_node;
}
// Removing the head item of the list
int
pop_head(node_t **head)
{
int retval = -1;
node_t *next_node = NULL;
if (*head == NULL) {
return -1;
}
next_node = (*head)->next;
retval = (*head)->val;
free(*head);
*head = next_node;
return retval;
}
// Removing the last item of the list
int
pop_last(node_t *head)
{
int retval = 0;
node_t *current = NULL;
if (head->next == NULL) {
retval = head->val;
free(head);
return retval;
}
/* get to the second to last node in the list */
current = head;
while (current->next->next != NULL) {
current = current->next;
}
/* now current points to the second to last item of the list.
so let's remove current->next */
retval = current->next->val;
free(current->next);
current->next = NULL;
return retval;
}
// Removing a specific item
int
remove_by_index(node_t **head, int n)
{
int i = 0;
int retval = -1;
node_t *current = *head;
node_t *temp_node = NULL;
if (n == 0) {
return pop_head(head);
}
for (i = 0; i < n - 1; i++) {
if (current->next == NULL) {
return -1;
}
current = current->next;
}
temp_node = current->next;
retval = temp_node->val;
current->next = temp_node->next;
free(temp_node);
return retval;
}
int
main(int argc, const char *argv[])
{
int i;
node_t * testnode;
for (i = 0; i < argc; i++)
{
push_head(&testnode, atoi(argv[i]));
}
print_list(testnode);
return 0;
}
// http://www.learn-c.org/en/Linked_lists
// https://www.geeksforgeeks.org/data-structures/linked-list/
The linked list implementation inspired by the implementation used in the Linux kernel:
// for 'offsetof', see: https://stackoverflow.com/q/6433339/5447906.
#include <stddef.h>
// See: https://stackoverflow.com/q/10269685/5447906.
#define CONTAINER_OF(ptr, type, member) \
( (type *) ((char *)(ptr) - offsetof(type, member)) )
// The macro can't be used for list head.
#define LIST_DATA(ptr, type, member) \
CONTAINER_OF(ptr, type, member);
// The struct is used for both: list head and list nodes.
typedef struct list_node
{
struct list_node *prev, *next;
}
list_node;
// List heads must be initialized by this function.
// Using the function for list nodes is not required.
static inline void list_head_init(list_node *node)
{
node->prev = node->next = node;
}
// The helper function, mustn't be used directly.
static inline void list_add_helper(list_node *prev, list_node *next, list_node *nnew)
{
next->prev = nnew;
nnew->next = next;
nnew->prev = prev;
prev->next = nnew;
}
// 'node' must be a list head or a part of a list.
// 'nnew' must not be a list head or a part of a list. It may
// be uninitialized or contain any data (even garbage).
static inline void list_add_after(list_node *node, list_node *nnew)
{
list_add_helper(node, node->next, nnew);
}
// 'node' must be a list head or a part of a list.
// 'nnew' must not be a list head or a part of a list. It may
// be uninitialized or contain any data (even garbage).
static inline void list_add_before(list_node *node, list_node *nnew)
{
list_add_helper(node->prev, node, nnew);
}
// 'node' must be part of a list.
static inline list_node *list_del(list_node *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
return node->prev;
}
Example of usage:
#include <stdio.h>
// The struct must contain 'list_node' to be able to be inserted to a list
typedef struct
{
int data;
list_node node;
}
my_struct;
// Convert 'list_node *' to 'my_struct*' that contains this 'list_node'
static inline my_struct* get_my_struct(list_node *node_ptr)
{
return LIST_DATA(node_ptr, my_struct, node);
}
void print_my_list(list_node *head)
{
printf("list: {");
for (list_node *cur = head->next; cur != head; cur = cur->next)
{
my_struct *my = get_my_struct(cur);
printf(" %d", my->data);
}
printf(" }\n");
}
// Print 'cmd' and run it. Note: newline is not printed.
#define TRACE(cmd) \
(printf("%s -> ", #cmd), (cmd))
int main()
{
// The head of the list and the list itself. It doesn't contain any data.
list_node head;
list_head_init(&head);
// The list's nodes, contain 'int' data in 'data' member of 'my_struct'
my_struct el1 = {1};
my_struct el2 = {2};
my_struct el3 = {3};
print_my_list(&head); // print initial state of the list (that is an empty list)
// Run commands and print their result.
TRACE( list_add_after (&head , &el1.node) ); print_my_list(&head);
TRACE( list_add_after (&head , &el2.node) ); print_my_list(&head);
TRACE( list_add_before(&el1.node, &el3.node) ); print_my_list(&head);
TRACE( list_del (head.prev) ); print_my_list(&head);
TRACE( list_add_before(&head , &el1.node) ); print_my_list(&head);
TRACE( list_del (&el3.node) ); print_my_list(&head);
return 0;
}
The result of execution of the code above:
list: { }
list_add_after (&head , &el1.node) -> list: { 1 }
list_add_after (&head , &el2.node) -> list: { 2 1 }
list_add_before(&el1.node, &el3.node) -> list: { 2 3 1 }
list_del (head.prev) -> list: { 2 3 }
list_add_before(&head , &el1.node) -> list: { 2 3 1 }
list_del (&el3.node) -> list: { 2 1 }
http://coliru.stacked-crooked.com/a/6e852a996fb42dc2
Of course in real life you will most probably use malloc for list elements.
In C language, we need to define a Node to store an integer data and a pointer to the next value.
struct Node{
int data;
struct Node *next;
};
To add a new node, we have a function add which has data as an int parameter. At first we create a new Node n. If the program does not create n then we print an error message and return with value -1. If we create the n then we set the data of n to have the data of the parameter and the next will contain the root as it has the top of the stack. After that, we set the root to reference the new node n.
#include <stdio.h>
struct node
{
int data;
struct node* next;
};
int main()
{
//create pointer node for every new element
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
//initialize every new pointer with same structure memory
head = malloc(sizeof(struct node));
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 18;
head->next = second;
second->data = 20;
second->next = third;
third->data = 31;
third->next = NULL;
//print the linked list just increment by address
for (int i = 0; i < 3; ++i)
{
printf("%d\n",head->data++);
return 0;
}
}
This is a simple way to understand how does pointer work with the pointer. Here you need to just create pointer increment with new node so we can make it as an automatic.
Go STL route. Declaring linked lists should be agnostic of the data. If you really have to write it yourself, take a look at how it is implemented in STL or Boost.
You shouldn't even keep the *next pointer with your data structure. This allows you to use your product data structure in a various number of data structures - trees, arrays and queues.
Hope this info helps in your design decision.
Edit:
Since the post is tagged C, you have equivalent implementations using void* pointers that follow the basic design principle. For an example, check out:
Documentation | list.c | list.h
Related
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
I have a text file consists of multiple journal entries which I can read it and store it into a struct called Journal. But my problem now is that I dont know how to add it into the linked list 1 by 1.
this is my insert method
void insertStart (LinkedList *list, Journal *JEntry) {
Node *newNode;
newNode = (Node*)malloc(sizeof(Node));
newNode->data.day = JEntry->day;
newNode->data.month = JEntry->month;
newNode->data.year = JEntry->year;
strcpy(newNode->data.entry, JEntry->entry);
if (list == NULL) {
list->head = newNode;
}
else {
newNode->next = list->head;
list->head = newNode;
}
printf("Inserted Entry = %d/%d/%d :%s\n", newNode->data.day, newNode->data.month, newNode->data.year, newNode->data.entry);
}
and this is
fscanf(fo, "%d", &numEntry);
journal = (Journal *)malloc(numEntry * sizeof(Journal));
for (i=0; i<numEntry;i++) {
fscanf(fo, "%d/%d/%d\n", &journal[i].day, &journal[i].month, &journal[i].year);
fgets(journal[i].entry, SIZE, fo);
}
insertStart(list, journal);
index = atoi(argv[1]);
printf("%d-%02d-%02d: %s\n", journal[index].year, journal[index].month, journal[index].day, journal[index].entry);
free(journal);
fclose(fo);
}
this is my struct
#define SIZE 102
typedef struct {
int day;
int month;
int year;
char entry[SIZE];
} Journal;
typedef struct Node {
Journal data;
struct Node *next;
} Node;
typedef struct {
Node *head;
} LinkedList;
if I put the insertStart in the for loop, yes it entered 4 times, but its the same result over and over again.
if i put it to where it is shown above, it will only run 1 time.
my question now is how can i store the rest of the entry into the linked list? thank you
this is the content of the text file
4
12/04/2010
Interview went well I think, though was told to wear shoes.
18/04/2010
Doc advised me to concentrate on something... I forget.
03/05/2010
Was asked today if I was an art exhibit.
19/05/2010
Apparently mudcakes not made of mud, or angry wasps.
the first number 4 is the number of entries in case anyone's wondering.
Have you considered just storing JEntry in the node instead of making a copy?
typedef struct
{
Journal* data;
struct Node* next'
}
Node;
That way this can be simplified
void insertStart (LinkedList *list, Journal *JEntry)
{
Node* newNode = malloc(sizeof(Node));
newNode->data = JEntry;
newNode->next = NULL;
instead of having a
struct { Node* head } LinkedList
just declare it
Node* list;
if you want to change the pointer pass it in as a double pointer
void insertStart( Node** list, Journal* JEntry) /* insertStart(&list,journal + i) */
If list already has an entry, make sure your new node points to that
if (*list != NULL)
{
newNode->next = *list;
}
Now make your list point to the new node
*list = newNode;
When printing use -> for JEntry as well.
printf("Inserted Entry = %d/%d/%d :%s\n", newNode->data->day, newNode->data->month, newNode->data->year, newNode->data->entry);
First, you need to set list->head to NULL when you create it (or use calloc instead of malloc).
However, your problem comes from the line insertStart(list,journal);. Although journal is the pointer to the beginning of an array of Journal objects, insertStart doesn't know that. It dereferences the pointer and only adds the first journal entry to the list.
I'm having trouble writing a function that will delete a node on a generic linked list.
I have my linked list declared as follow (this is the way my professor wants us to do):
typedef enum _STATUS {ERROR,OK} STATUS;
typedef enum _BOOLEAN {FALSE, TRUE} BOOLEAN;
#define MAX_NOME 20
typedef struct _FUNC
{
char name[MAX_NOME];
char dept[MAX_NOME];
BOOLEAN permanent;
} FUNC;
typedef struct _LIST_NODE
{
void * data;
struct _LIST_NODE * next;
} LIST_NODE;
typedef LIST_NODE * LIST;
#define DATA(node) ((node)->data)
#define NEXT(node) ((node)->next)
I've come with this function to delete all nodes with permanent == FALSE, but it is really not working.
void DeleteFuncNotPermanent(LIST *list)
{
LIST *node = list;
while ((*list)->next != NULL)
{
if(((FUNC*)DATA(*list))->permament == FALSE)
{
node = list;
list = &(NEXT(*node));
free(DATA(*node));
free(*node);
}
else
{
list = NEXT(*list);
}
}
}
Any feedback would be greatly appreciated. Thank you.
You iterate through the list with a pointer to node pointer, which is a good idea. (Typecasting away the pointer nature of LIST is not a good idea, however.) There are several errors in yur code.
To get a pointer to the last element of a list, you do:
Node **p = &head;
while (*p) {
p = &(*p)->next;
}
Your respective code, i.e. your function without the deletion stuff, looks like this:
while ((*list)->next != NULL) {
list = NEXT(*list);
}
You should iterate while (*list). The idea to check next probably stems from similar code that uses a node pointer to iterate. When you use a pointer to node pointer, dereferencing that pointer has the same effect as accessing next, because that pointer points to the head node at first and to the previous node's next member on subsequent iterations.
That's why you must assign the address of (*list)->next to list when you want to advance the pointer. (The comiler warns you that the pointer types don't match.)
So the "raw" loop should be:
while (*list != NULL) {
list = &NEXT(*list);
}
Now let's look at deletion. When you have determined that the node should be deleted, you do:
LIST *node = list;
list = &(NEXT(*node));
free(DATA(*node));
free(*node);
Here, you do not want to advance the iterator pointer. Instead, you want to update what it points at: You want to skip the current node *list by deflecting the pointer that points to the node to the next node or to NULL, when that was the last node:
*list = NEXT(*node);
When you do that, list and node will still be the same address, only the contents have changed. (Because node == list, *node now points at the node after the node you want to delete and you accidentally free that node and its data. Make the temporary pointer a simple node pointer:
LIST node = *list;
*list = NEXT(node);
free(DATA(node));
free(node);
Putting it all together:
void DeleteFuncNotPermanent(LIST *list, int c)
{
while (*list)
{
if (((FUNC*) DATA(*list))->permament == FALSE)
{
LIST node = *list;
*list = (NEXT(*list));
free(DATA(node));
free(node);
}
else
{
list = &NEXT(*list);
}
}
}
I have tried to rewrite your delete function. Let me know if it works. The changes are basically related to pointer dereferencing.
void DeleteFuncNotPermanent(LIST *list)
{
LIST *node = list;
while (list!= NULL) // change
{
if(((FUNC*)(DATA(list)))->permament == FALSE) // change
{
node = list;
list = NEXT(node); //change
free((FUNC*)(DATA(node))); // change
free(node); // change
}
else
{
list = NEXT(list); //change
}
}
}
I'm currently doing an assignment for uni and I need to find the sum of a graph.
To do this I believe I need a linked list that I can use to remember which nodes have been visited. I have the linkedlist working correctly but I can't get a contains function to work. This is the code I have:
struct listnode
{
struct N *val;
struct listnode *next;
};
int contains(struct listnode *head,struct N* value)
{
struct listnode *current = head;
while (current)
{
if ((current -> val) == value)
{
return 1;
}
current = current -> next;
}
return 0;
}
note: N is a node of the graph.
Can anyone see any problems with what I'm doing?
EDIT: contains function should return 1 when N *value is in the list, 0 otherwise
EDIT2:
I have a push function:
void push(struct listnode *head,struct N *value)
{
if (head)
{
struct listnode *current = head;
while (current->next)
{
current = current -> next;
}
current->next = malloc(sizeof(struct listnode*));
current->next->val = value;
current->next->next = NULL;
}
else
{
head = malloc(sizeof(struct listnode*));
if (head)
{
head -> val = value;
head -> next = NULL;
}
else
{
printf("error");
exit(0);
}
}
}
and I want the following line to return 1:
contains(push(visited,p),p);
where p is a pointer to a struct N and visited is my global linked list
EDIT3:
this is my final sum function that I believe should work, but doesnt because of contains.
long sum(struct N *p)
{
if (p)
{
if (contains(visited,p) == 0) //if p hasnt been visited
{
push(visited,p); //make it visited
return (p -> data) + sum(p -> x) + sum(p -> y) + sum(p -> z);
}
else
{
return 0;
}
}
else
{
return 0;
}
}
Your contains function appears to be fine. The issue is that you are always passing a NULL list to it, which is caused by a faulty push function. You need a return in push, or to pass in a pointer with one more level of indirection, so you can assign to head outside of push. One more possible improvement is to notice that no matter what you pass in, the malloc and initialization of a new node is actually the same.
Finally, the main issue, that is really the most likely to cause a segfault is the fact that you are allocating enough space for a pointer to a node, not for the node itself.
Here is an example:
#ifdef BY_INDIRECTION
#define RET_TYPE void
#define IN_TYPE struct listnode **
#else
#define RET_TYPE struct listnode *
#define IN_TYPE struct listnode *
#endif
RET_TYPE push(IN_TYPE head, struct N *value)
{
struct listnode *current, **next;
if(head)
{
for(current = head; current->next; current = current->next) ;
next = &(current->next);
}
else
{
#ifdef BY_INDIRECTION
next = head;
#else
next = &head;
#endif
}
*next = malloc(sizeof(struct listnode));
if(!*next) {
printf("error");
exit(0);
}
(*next)->val = value;
(*next)->next = NULL;
#ifndef BY_INDIRECTION
return head
#endif
}
I have included both suggestions here. If you want to read the one where we use indirection (pass in a listnode ** and have void return), choose the path where BY_INDIRECTION is defined. If you want to have head returned (and pass in just a regular listnode *) read the path where BY_INDIRECTION is not defined.
The latter approach has a return value, so it can be used to write a shortened form like if(contains(push(head, value), value)) { ... }. The former approach does not, so you would have to do
push(&head, value);
if(contains(head, value)) { ... }
I would recommend using the indirect approach regardless because there are very few instances that you would want to check for containment after putting in a value.
This comparison:
if ((current -> val) == value)
it's comparing pointers. If you call your contains() function this way...
...
struct N val_to_find;
...
result = contains (list, &val_to_find);
You will never find the value, even if the contents of val_to_find are the same as the contents of any struct whose pointer is stored in the list.
If your intention for contains() is to find nodes that have the same data, and not just the same pointers, I'd suggest you something like this:
if (struct_n_comparing_function (current -> val, value) == EQUAL) ...
Where struct_n_comparing_function should have the following prototype:
int struct_n_comparing_function (struct N *a, struct N *b);
which compares the contents of the two structs pointed by a and b and return EQUAL if all the fields of the struct pointed by a have the same value as the fields of struct pointed by b.
I am using a struct to store a string and an integer like so:
struct movement {
char *direction;
int steps;
};
I can add items into the struct by doing this
struct movement m1= { "right",20 };
struct movement m2= { "left" ,10 };
The end result I am trying to achieve is to collect user inputs (e.g. "right 20"), and store it in the struct. How can I store an unknown number of user inputs into the struct without the use of variables (m1, m2 etc) since I will not know how many items there will be at the end.
It doesn't sound as if you really want to "store values into the struct", instead you want to store a sequence of independent struct instances; one for each user input.
The three most basic ways of doing this are:
An array, whose size you select at compile-time. It shouldn't be too hard to make it "large enough" for reasonable input
An array whose size you set (and then grow) at run-time
A linked list of structure instances
Which one to prefer depends on which you think is simplest. If at all possible, a static appeoach is always simplest. You can easily have something like
struct movement movements[10000];
at the global level, this will only cost perhaps 120 KB on a 64-bit system. Note though that this doesn't include memory for the direction strings; if those are always chosen from "right" and "left" (and perhaps "up"/"down" too) you could represent it as an enum instead:
enum direction { DIRECTION_LEFT = 0, DIRECTION_RIGHT, DIRECTION_UP, DIRECTION_DOWN };
This will make the structure "self-contained" and (on 64-bit systems) smaller since the enumeration will be smaller than a pointer.
Dynamically growing an array using realloc() isn't too hard, you could look that up easily as its often used.
Use a linked list. It is a recursive data structure which would be great for what you want.
Here is some example code I wrote a while ago that might help:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* basic linked list structure */
typedef struct node node_t;
struct node {
char *direction;
int steps;
node_t *next;
};
/* pointers to the head and tail of the list */
typedef struct {
node_t *head;
node_t *foot;
} list_t;
list_t *initialize_list(void);
list_t *insert_nodes(list_t *list, char *direction, int steps);
void free_list(list_t *list);
node_t *generate_node(void);
void print_list(list_t *list);
void exit_if_null(void *ptr, const char *msg);
int
main(int argc, char const *argv[]) {
list_t *list;
/* empty list created */
list = initialize_list();
/* inserting information one a time */
list = insert_nodes(list, "right", 20);
list = insert_nodes(list, "left", 10);
print_list(list);
/* freeing list at the end */
free_list(list);
list = NULL;
return 0;
}
/* function to insert information into a node */
list_t
*insert_nodes(list_t *list, char *direction, int steps) {
/* called generate_node() to create a new node */
node_t *new;
new = generate_node();
/* puts steps information into node */
new->steps = steps;
/* allocates space for direction string */
/* this is needed because *direction is a pointer */
new->direction = malloc(strlen(direction)+1);
/* copies direction info into node */
strcpy(new->direction, direction);
/* inserting information at the tail of the list */
new->next = NULL;
if (list->foot == NULL) {
/* first insertion into list */
list->head = list->foot = new;
} else {
list->foot->next = new;
list->foot = new;
}
/* returns modified list */
return list;
}
.* function which generates new nodes */
node_t
*generate_node(void) {
node_t *newnode;
/* create space for new node */
newnode = malloc(sizeof(*newnode));
exit_if_null(newnode, "Allocation");
/* initialize node info to nothing */
newnode->direction = NULL;
newnode->steps = 0;
return newnode;
}
/* creates the empty linked list */
list_t
*initialize_list(void) {
list_t *list;
create space for list */
list = malloc(sizeof(*list));
exit_if_null(list, "Allocation");
/* set pointers to NULL */
/* We don't want them pointing at anything yet */
list->head = list->foot = NULL;
return list;
}
/* function which prints entire list */
void
print_list(list_t *list) {
/* start at the head of the list */
node_t *curr = list->head;
while (curr) {
printf("%s %d\n", curr->direction, curr->steps);
/* steps through the list */
curr = curr->next;
}
}
/* function which frees nodes */
void
free_list(list_t *list) {
node_t *curr, *prev;
/* start at beginning of list */
curr = list->head;
/* frees nodes one at a time */
while(curr) {
prev = curr;
curr = curr->next;
free(prev);
}
/* frees entire list */
free(list);
}
/* function which checks malloc(), and whether enough space was allocated */
void
exit_if_null(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}
Use a LinkedList to store an indefinite number of movements.
For each movement, create a node in the linked list and update the next pointer.
struct node {
struct movement m;
node* next;
}