C - Creating a dynamic array of structs, struct members printing wrong values? - c

I am trying to create a dynamic array of players which I can add to during run time - however if I create 3 players with x-coords: 4,7 and 15, then try to print these values the output is: 0, 33, 20762704.
I am new to C and pointers and am struggling to work out where it is going wrong.
#include <stdio.h>
#include <stdlib.h>
// contains data of a player
struct player {
int posX;
int posY;
int gold;
};
// struct for creating a list of players of dynamic size
struct playerList {
struct player p;
struct playerList *next;
};
// add a new player to the list with given coords
struct playerList *make(int x, int y) {
struct playerList *new_player;
new_player = (struct playerList *)malloc(sizeof(struct playerList));
new_player->p.posX = x;
new_player->p.posY = y;
new_player->p.gold = 0;
new_player->next = NULL;
return new_player;
}
// add a player to the list
void addPlayer(struct playerList *list, int x, int y) {
if(list->next) {
addPlayer(list->next,x,y);
}
else {
list->next = make(x,y);
}}
int main() {
struct playerList *players = (struct playerList *)malloc(sizeof(struct playerList));
addPlayer(players, 4,3);
addPlayer(players, 7,7);
addPlayer(players,15,1);
printf("%d\n",players[0].p.posX);
printf("%d\n",players[1].p.posX);
printf("%d\n",players[2].p.posX);
return 0;
}

In order to add the first player to the list, you must pass a pointer-to-pointer-to-playerList to addPerson because the first node address will become the list address. Otherwise, you must return type *playerList and assign the return to your list variable back in the calling function. It is just as easy to pass the playerList ** parameter to your function and return a pointer to indicate success/failure as well as for convenience. e.g.:
/* add a player to the list */
playerList addPlayer (struct playerList **list, int x, int y) {
struct playerList *node = make (x, y);
if (!node) { /* validate new player created */
fprintf (stderr, "error: make player failed for (%d,%d).\n", x, y);
return NULL;
}
if (!*list) /* if first node, set list address to node & return */
return *list = node;
struct playerList *iter = *list; /* list pointer to iterate to end */
/* insert all other nodes at end */
for (; iter->next; iter = iter->next) {}
iter->next = node; /* add new player at end, return original *list */
return *list;
}
Then in main
addPlayer(&players, 4,3);
...
(note: the addPlayer is no longer recursive. As your list size grows, the additional resources needed for recursive calls can become significant, further, there is no need for a recursive call as the procedural iteration to the end of list to add a new player is straight forward.)
Look over the change and let me know if you have any additional questions. (note: I have not checked the remainder of your code for further errors)

In the list, you have a node that you are going to save some data on it, and it points to the next node too. So, you could define list structure to maintain the head of your list, and probably some other required information such length of the list or garbage handling or ...
For initialization you should set the length with zero and head pointer of list to NULL, these steps show the empty status of the list.
When you want to add to the list, you could add at the end of it, or at the head of it. In your program, you choose the second insertion policy, at the end. So, to add, you should traverse the list (all nodes), to find the last node, to add new node after that one. You should be aware of adding the new node when the list is empty, in this case you should update the head of your list.
For printing, there is a similar way, you should traverse the list and print the node information of that, until you reach the null pointer at the end of list.
After any allocation you should check the allocation success, if the pointer is not null, it was successful.
Another point, when you can handle adding the new node with using a simple loop, why you should use the recursive function? In this cases, it is better to use the loop.
The last point, dynamic allocation memory used commonly when the number of the list is specified in the run time, for example. It is a good point, to less memory allocation if you don't have to use. For instance, in the main you could define the list variable as a static variable, and send the address of that to the functions.
I tested the program, and its output was okay.
#include <stdio.h>
#include <stdlib.h>
// contains data of a player
struct player {
int posX;
int posY;
int gold;
};
// struct for creating a list of players of dynamic size
struct playerNode {
struct player p;
struct playerNode *next;
};
struct playerList {
struct playerNode *head;
int len;
// Add other required variables here
};
// add a new player to the list with given coords
struct playerNode *make(int x, int y) {
struct playerNode *new_player;
// you need to check memory allocation success
new_player = malloc(sizeof(struct playerNode));
new_player->p.posX = x;
new_player->p.posY = y;
new_player->p.gold = 0;
new_player->next = NULL;
return new_player;
}
// add a player to the list
void addPlayer(struct playerList *list, int x, int y) {
struct playerNode *player = list->head;
if(!player)
// you need to check memory allocation success
list->head = make(x, y);
else
{
while (player->next) {
player = player->next;
}
// you need to check memory allocation success
player->next = make(x, y);
}
list->len++;
}
void showPlayers(struct playerList *list) {
struct playerNode *player = list->head;
while (player) {
printf("%d\n", player->p.posX);
printf("%d\n", player->p.posY);
printf("%d\n", player->p.gold);
printf("--------------------\n");
player = player->next;
}
}
int main() {
struct playerList players;
players.len = 0;
players.head = NULL;
addPlayer(&players, 4, 3);
addPlayer(&players, 7, 7);
addPlayer(&players, 15, 1);
showPlayers(&players);
return 0;
}

Related

Why my clear function with selected element does not work correctly?

during working on the project to school, i find a little problem, which i do not know remove.
Problem is in fuction clear_train. When i trying to remove 1. element, function return also my element(but empty).
Here is my source code where are definitions of all functions:
(in a_train.h are a declarations and descriptions of functions)
#include "a_train.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct car* add_car(struct car* first,const char* target) {
struct car* adder = malloc(sizeof(struct car));
struct car *current = first;
strcpy (adder->value,target);
adder->next=NULL;
if(first == NULL){
first =adder;}
else{
while (current->next != NULL) {
current = current->next;
}
current->next = adder;
}
return first ;
}
void print_train(struct car* first) {
if (first!=NULL){
while (first!=NULL){
printf("%s\n",first->value);
first=first->next;
}
}
else printf("empty list\n");
}
void cancel_train(struct car* first) {
while(first!=NULL){
struct car* canceler = first->next;
free(first);
first=canceler;
}
}
struct car* clear_train(struct car* first, const char* target) {
if(first == NULL){
return NULL;
}else if (first->next==NULL){
if(strcmp(first->value,target)==0){
free(first);
return NULL;
}else return first;
}
struct car* prev_searcher =first;
struct car* this_searcher =first;
while (this_searcher!=NULL){
if(strcmp(this_searcher->value,target)==0){
prev_searcher->next=this_searcher->next;
free(this_searcher);
}
prev_searcher=this_searcher;
this_searcher=this_searcher->next;
}
return first;
}
here is the definition of linked list:
struct car {
char value[SIZE];
struct car* next;
};
source code of main where i am calling functions:
int main(){
struct car* train = NULL;
train = add_car(train,"Presov");
train = add_car(train,"Bratislava");
train = add_car(train,"Levoca");
train = add_car(train,"Spiska Nova Ves");
train = add_car(train,"Bardejov");
train = add_car(train,"Pichne");
clear_train(train,"Presov");
print_train(train);
cancel_train(train);
return 0;
}
And finally there is output:
//there is empty node
Bratislava
Levoca
Spiska Nova Ves
Bardejov
Pichne
You are making things more difficult to remove a node from a linked list than it needs to be. While you are free to return and assign the head node each time clear_train is called, that's not really the way to do it.
Instead of passing a pointer-to-head (first) as the parameter to clear_train, pass the actual address of the head pointer, e.g.
clear_train(&train,"Presov");
That way you can manipulate the value (node) at that address directly. If the first node in the list is the one being delete, you simply update the node address held by the original pointer to the new first node and you are done.
Instead of trying to keep a previous, current and next node, simply use a pointer-to-pointer to current node. Then when the node containing target is found, you simply update the pointer at that address to the ->next node and you are done. See Linus on Understand Pointers
That reduces your clear_train function to:
void clear_train (struct car **first, const char* target) {
struct car **ppn = first; /* pointer-to-pointer to first */
struct car *pn = *first; /* pointer-to-first */
for (; pn; ppn = &pn->next, pn = pn->next) { /* iterate, find target */
if (strcmp (pn->value, target) == 0) { /* if found */
*ppn = pn->next; /* set pointer at target address = next */
free (pn); /* free node contianing target */
break;
}
}
}
Much simpler than trying to test for different cases of where the node lies.
In clear_train
when you find the car - you free the element and then you try to get to it again so the program will make you problem.
write like this
if(strcmp(this_searcher->value,target)==0){
prev_searcher->next=this_searcher->next;
free(this_searcher);
return prev_searcher}

How can I add items into a struct without creating variables

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

creating printing and counting linked lists using recursion

i tried to create linked list as follows but the output comes a fixed list
of two elements and count to be 2
#include<stdio.h>
#define null 0
struct list
{
int num;
struct list *next;
};
typedef struct list node;
int create(node *list)
{ int n;
printf("enter the element to end the list finish it with -999\n");
scanf("%d",&n);
if(n==-999)return 0;
else {
list=(node *)malloc(sizeof(node *));
list->num=n;
if(!(create(list->next)))list->next=null;
return 1}
}
void printlist(node * list) {
if(list->next==null)
{printf("%d->",list->num);return;}
else
{printf("%d->",list->num);printlist(list->next);}
return;
}
int count(node *list) {
if(list->next==null)return 1;
else return(1+count(list->next));
}
void main() {
node *list;
create(list);
printlist(list);
printf("\n%d",count(list));
}
is there any problem with passing pointer to the function.
When you pass in a pointer to create it creates a copy of the pointer. That is, if you modify list in create it will not change the value of list in main.
Try passing in the pointer to list in main to create. This will allow you to cange list inside create.
// in main:
create(&list)
// in create
int create(node** listptr) {
// similar code to before except
// that list should be replaced with
// (*listptr)
//
// the example below will assing a value
// to the variable list in main:
// (*listptr) = x
// ...
}
Print should work as is. It doesn't need a node** as it won't change the list.

Using malloc with structures in a function

HERE IS MY INSTRUCTIONS FOR THIS FUNCTION: Here an unsigned integer listsize is passed to this function you are to create a link list of size listsize. This will be performed by repeated use of malloc and calling setData to initialize the data into the struct plane fields. Each time you place the process in the list you need to place it so the list is sorted by the field distance (in ascending order). you return the head of the list
struct plane* list_intialize(unsigned int num)
{
struct plane *ptr,*head;
int i=0;
ptr = (struct plane*) malloc(num * sizeof(struct plane));
for (i = 0; i < num; ++i)
setData(ptr+i);
return ptr;
}
This started as a function skeleton inside an already completed program....I'm to complete the function so that it creates a link list. The setData is given function that inserts data to the structure elements.....MY problem is that after I run the current function it only returns one plane with information instead of num amount....am I using setData wrong or should my current setup work
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef _MY_DEF_
#define _MY_DEF_
enum dir {NE=0, EN, NW, WN, SE, ES, SW, WS};
enum loc {LNE=0, LNW,LSE,LSW};
struct plane{
short flightCode;
long xCord;
long yCord;
double distance;
char direction;
enum dir flightPattern;
enum loc location;
struct plane *nextPlane;
};
#endif
struct plane* sortByDist(struct plane*);
struct plane * radarPrint(struct plane*head);
int checkPlane(struct plane *);
int checkForCollision(struct plane*);
void setData(struct plane *pLane);
You need to allocate your list by allocating each node. One way of doing that while chaining the list forward is the code below:
struct plane* list_intialize(unsigned int num)
{
struct plane *head, **pp = &head;
int i=0;
for (i=0; i<num; ++i)
{
*pp = malloc(sizeof(**pp));
setData(*pp);
pp = &(*pp)->nextPlane;
}
*pp = NULL;
return head;
}
How It Works
This uses a pointer-to-pointer to always hold the address of the location where the nextPlane dynamo node address is stored. It starts with the address of the head pointer. With each new node, pp is filled the address of that node's nextPlane member. Once finished, it holds the address of the last node's nextPlane pointer, which it sets to NULL. The first node, pointed to by head, is returned. (and yes, this works even if you passed num = 0 for the requested size, in which case you would get back zero nodes: i.e. NULL).
Note: Don't forget, you need to free each node when releasing the list, extracting a single node out, etc. For example, to delete an entire list:
void list_delete(struct plane **lst)
{
while (*lst)
{
struct node *victim = *lst;
*lst = victim->nextPlane;
free(victim);
}
}
Invoked like this:
struct plane *lst = list_initialize(N);
// use list.., maybe adding nodes, removing them, changing, etc...
list_delete(&lst);
How to print your list:
void list_print(const struct plane *lst)
{
while (lst)
{
// TODO: print list node pointed to by lst.
// Ex: (x,y) coords
printf("(%d,%d) ",lst->xCord, lst->yCord);
lst = lst->nextPlane;
}
printf("\n");
}
You are not setting the links between the objects. In the for loop, you need:
ptr[i]->nextPlane = ptr[i+1];
At the end of the loop, make sure the last object points to NULL.
ptr[i-1] = NULL;

How to implement a linked list in C?

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

Resources