Inventory system approach - c

So I'm creating a system to control inventory. I have a text file which contains all the items in the inventory.
as:
{component, stock code, count, price}
I am creating a struct to represent the stock (this is done in a header file):
typedef struct StockItem {
char *componentType;
char *stockCode;
int numOfItems
int price;
} StockItem;
I want to have a struct in which controls the entire inventory as a linked list, was wondering how would I do it so it would have a collection of StockItems. ( would this be a good way to do it)?
Also one more question, is it conventional to have the struct as a capital letter or not ?
EDIT:
typedef struct inventory {
struct StockItem item;
struct inventory *next;
}inventory;
inventory *pFirstNode = NULL;
inventory *pLastNode = NULL;
void createNewList(struct StockItem *item){
// Set aside enough space in memory for this struct
inventory *pNewStruct = (inventory*) malloc(sizeof(inventory));
// We can assign the value directly for the structs
// reference for the next struct in the linked list
pNewStruct->next = NULL;
printf("Enter Product Name: ");
// The & is needed only because scanf() is used
pNewStruct->item = item;
// When the first struct is created all of the following
// refer to the same struct
pFirstNode = pLastNode = pNewStruct;
}

If a linked list is suitable in your case really depends on how you want to access your inventory. If you plan only to go through it in sequence a linked list is good. If you store an index to a specific inventory item and later retrieve that item out of your list, thats going to be incredibly slow. In this case a datastructure with an array (std::vector for example) is better. But all of that also depends on the amount of data you have. Theres nothing wrong querying a linkedlist by index that only has 100 elements. For your specific question on how you can create a collection, are you limited to c, or can you use c++? The std namespace has a lot of useful collections including an implementation for a linkedlist and a vector which basically is an array, that dynamically resizes.
As you want to limit yourself to c, you will have to write your list implementation yourself. Its nothing that i would recommend somone who is still learning though. Implementing a decent list is really difficult. But if you really want to, this might be a good start. You also learn how linked lists work under the hood, which is a good thing considering a lot of people missuse linkedlists and wonder about bad performance afterwards.
Lets take the link above as an example. They defined a node struct:
typedef struct node {
int val;
struct node * next;
} node_t;
The field "val" is type int. In your case this will be the type of item, that you want to store in your list. Its going to be StockItem or a pointer to a StockItem, depending on how you want to manage your memory. If you want to add a StockItem to the list, you wrap it into a node and assign the pointer to that node to the "next" field of the previous node. Everything is also really well explained in the link i provided.
What you got so far is fine. Next, to add a node to your list, you should set the lastNode pointer and the next pointer in lastNode:
pLastNode->next = pNewStruct;
pLastNode = pNewStruct;

Related

Returning a list as a data structure contract

I am working on a shared library (aka dll) implementation that can be consumed by other C programs. As a data contract, I wish to be able to return a list of variable length from one of my methods. Say, the structure I wish to return is my_data_type, what should I put as a contract data structure?
I can think of something like this:
struct data_type_list
{
my_data_type* data_list;
int count;
};
where the consumer knows there are count elements in the list and consumer terminates the array at data_list[count-1].
Any other ideas?
It really depends on how the user of your library utilizes the returned data. I would probably go with your solution if the data is pretty much read-only (in a sense that the user doesn't want to write to it but just iterates over every element pointed to by data_type_list.data_list). If the user wants to do extensive modifications like adding to or deleting data, a linked list would be the preferred data structure to use, I think:
/* example of a node in a singly-linked list */
struct list_node {
void *data;
struct list_node *next;
}
A NULL pointer indicates the end of the list while data can be accessed using the data member of every node. You could of course add a struct list_node *prev member that points to the previous node, too (yielding a doubly-linked list).

Struggling to form a linked list

I am working on a problem that involves creating an inventory of supermarket stock, and I'm having considerable difficulties. What the program is supposed to do is prompt a user for input (item name, quantity, weight, and price) and then add this item into a sorted (by increasing alphabetical order) database.
So my idea is to create a linked list. I've started by defining the following:
typedef struct item_t item;
struct item_t{
char name;
int weight;
int price;
int quantity;
item *next;
};
So the idea that I'm going for is that every item has its details stored in this structure type, and that *next will point to the next structure in the linked list.
Next I came up with this:
void add_new_node_at_end(char *user_input){
new_node = (*item_t)malloc(sizeof(item_t))
if (new_node == NULL){
printf("Memory failure");
exit(EXIT_FAILURE);
}
}
Is this correct so far?
Now, I'm not too sure what to do about the pointer *next when I create a new node, nor do I know how to change the fields of the structure. Can I simply use new_node.item = 'string' or do I need to malloc the field names as well?
Sorry, this might be a silly question but I really need someone to point me in the right direction.
You need one global root pointer (item_t* root) and initialize it with NULL which is the start of your list. For a single-linked list, point the next pointer of the new element to the element pointed at by root, and change root to point to the newly created element.
By doing this, you create daisy-chain of elements. The end is reached when item.next == NULL .

How to reuse code for a list (or how to deal with 2 different functions for lists of different types of structs)

The idea: a list of lists (for a publisher-suscriber problem)
The problem: the lists use different types of structs as nodes. So my function does not work with the second type of struct (that's just fine, I could simply create another function and just change the parameters that it uses).
But I feel that's a rather simplistic approach and honestly the amount of code I'm beggining to handle is a bit too much.
Is there a more professional/experienced way to do this? (that I can handle. For example here they talk about it but I'm not quite sure I could implement it without messing up since I've never used unions:
How to Pop different types of Structs from a Stack
)
Is this a common/aceptable way of doing things (reusing functions for different structs/data types)?
Structs I use:
struct nodoTemas{
char * nombreTema;
struct nodoSuscriptor * nodoCerodeSuscriptores;
struct nodoTemas * next;
};
struct nodoSuscriptor{
char * nombreSuscriptor;
//int iP;
struct nodoTemas * next;
};
So I have a working code with a function that creates the list , and other similar methos to interact with it.
struct nodoTemas* create_list(char * val, struct nodoTemas * head, struct nodoTemas *curr)
{
printf("\n creating list with headnode as [%s]\n",val);
struct nodoTemas *ptr = (struct nodoTemas*)malloc(sizeof(struct nodoTemas));
if(NULL == ptr)
{
printf("\n Node creation failed \n");
return NULL;
}
ptr->nombreTema = val;
ptr->next = NULL;
head = curr = ptr;
printf("Ha llegado aqui3\n");
return ptr;
}
I provided this much code because I'm usually asked to do so. As always I'm sorry if this is not the right place/the question is not worded properly.
EDIT: I have now find out that with union and struct, it'd hold space for the biggest of the two or more types. I am not sure if this is just wasting too much space and thus making that a not so good option, so not quite sure how to do it (the idea being that if if it's a list of suscribers, it could be 2 or 2000, and with each node added there'd be wasted space).
The problem you are struggling with - how to create reusable generic functionality, such as containers - is one which is addressed easily with object oriented programming languages such as C++. However they can be implemented in C, even if not as easily and flexibly.
The key is to identify which functionality is common and generic, and which is specific to the types of nodes in the list.
Generic functionality would be the functions such as creating/initializing the list, adding nodes, deleting nodes, iterating through the list, etc.
Create stand alone functions for handling lists, together with a struct that models the generic nodes.
Then, create structures representing the different object types in the list. Embed one of the generic list node structs as the first element in each of these structs, and write functions as needed to provide the functionality for handling each of the different types of objects you need to deal with.
In that way you end up with generic, re-usable lists, and as an added bonus you keep your code for dealing with the specific object types clean and easily maintainable.
Here is a simple program I whipped up to demonstrate the principle. It allows creating a list of objects representing apples and oranges. The apples have functionality for tracking their weight, and the oranges have functionality for tracking their price.
#include <stdio.h>
#include <stdlib.h>
/* First we start with the definition of a generic list node */
struct list_node {
struct list_node *next;
struct list_node *prev;
/* The 'type' field is important - it allows us to have a list
* containing a number of different types of node, and to be able
* to find out what type each node is */
int type;
};
/* Some variables to keep track of the beginning and end of the list. */
struct list_node* head;
struct list_node* tail;
/* Now some generic functions for dealing with lists - initializing the list,
* adding nodes through it, iterating through the list */
void list_init() {
head=tail=NULL;
}
void list_add_node(struct list_node* node) {
if (NULL==tail) {
head=tail=node;
node->next=NULL;
node->prev=NULL;
} else {
tail->next=node;
node->next=NULL;
node->prev=tail;
tail=node;
}
}
struct list_node* list_get_next(struct list_node* node) {
if (NULL==node)
return head;
else
return node->next;
};
/* Great, now we have a generic set of functions for dealing with generic lists.
* But how do we use that to contain different kinds of objects? The answer
* is composition - we include the list_node as the first element of each of the
* structs that we want to add to the list
*
*
* Here we define a struct for recording the weight of apples, together with
* functions specific to dealing with apples
*/
struct apple {
struct list_node node;
int weight;
};
struct apple* new_apple(int weight) {
struct apple* a = (struct apple*)malloc(sizeof(struct apple));
/* Apples are considered type 1 */
a->node.type = 1;
a->weight = weight;
return a;
};
void apple_printweight(struct apple* a) {
printf("This is an apple and it weighs %d grams\n", a->weight);
}
/* And here we define a struct for recording the price of oranges, together with
* functions specific for dealing with oranges
*/
struct orange {
struct list_node node;
double price;
};
struct orange* new_orange(double price) {
struct orange* o = (struct orange*)malloc(sizeof(struct orange));
/* Oranges are type 2 */
o->node.type = 2;
o->price=price;
return o;
};
void orange_printprice(struct orange* o) {
printf("This is an orange and it costs $%6.2f dollars\n", o->price);
}
/* Now to use our oranges and apples */
int main() {
list_init();
/* Create an orange, add it to the list
*
* Note the need to cast the orange to a list_node
* so we can call the 'list_add_node' function.
* This makes use of a property of pointers to structs:
* you can always convert them to point to the first element of
* the struct.
*/
struct orange* myOrange = new_orange(12.50);
list_add_node((struct list_node*)myOrange);
/* Create an apple, add it to the list */
struct apple* myApple = new_apple(150);
list_add_node((struct list_node*)myApple);
/* Iterate through the list */
struct list_node* n = NULL;
while (n = list_get_next(n)) {
/* For each node we come to, it could be an apple or an orange.
* Inspect the type to find out what type it is, and use it
* accordingly */
if (n->type == 1) {
apple_printweight((struct apple*)n);
} else if (n->type == 2) {
orange_printprice((struct orange*)n);
}
}
/* In a real program you would want to free the list objects here
* to avoid a memory leak
*/
}
Here is the output:
This is an orange and it costs $ 12.50 dollars
This is an apple and it weighs 150 grams
Bear in mind that this is just a simple example, and by no means does it illustrate best practice in all aspects. In real life you would separate the declarations into header files, and you would probably do something more elegant than the if/then branching in the main loop to handle the different types.
I'm struggling to find a reason why you're casting mallocs return value. It seems, if you want C++ compatibility, just nuke C and adopt C++'s linked lists and your life gets so much easier. As you're about to see, generics in C can be a pain in the butt! If you want to write C code, nuke the casts. If you want to reuse the C code in a C++ project, compile it using a C compiler and link to it using the compatible C++ compiler.
Yes, you'll want to eliminate redundant code. The first step to making your life that much easier is to eliminate malloc from your linked list code. Pass all allocated data in via arguments, just like sprintf requires. There is a reason sprintf was designed like that. Liberation of data-specific context goes hand-in-hand with liberation of allocation. That probably means your linked list struct will contain only one member: A pointer to the next node, eg struct linked_list_node { struct linked_list_node *next; };... So be it! You can declare new list types like so, and use the functions you've created to handle the generic list type:
struct apple_linked_list {
struct linked_list_node linked_list;
char *colour;
};
struct apple_linked_list_linked_list {
struct linked_list_node super_list;
struct apple_linked_list_node *sub_list;
};
struct apple_linked_list red = { .colour = "red" },
blue = { .colour = "blue" },
green = { .colour = "green" },
*root = NULL;
root = linked_list_add(root, &red);
root = linked_list_add(root, &blue);
root = linked_list_add(root, &green);
struct apple_linked_list_linked_list list_list = { .sub_list = root };
struct apple_linked_list_linked_list *super_root = NULL;
super_root = linked_list_add(super_root, list_list);
So now you want malloc back. I can't say I blame you. It is a useful tool... but it's not to be inserted into your existing add function, because it's also useful to be able to create non-malloc'd lists. Kinda like how it's useful to be able to use sprintf without requiring malloc or free... Write a new struct to extend the old, and a new set of functions to operate on this struct. This gets a little more complex, but it's still possible. It might also be sensible to rename your previous types and functions to automatic_linked_list.
I've written all of this code and tested it, and I'm prepared to offer it to the public domain here.
Hope this helps :)

How to keep track of and sort pointers without using malloc in C?

I would like to know if anyone has a suggestion for keeping track of and sorting some pointers. Each pointer points to a struct (struct1_t) which contains some elements.
I also need to be able to (very quickly) find the struct1_t with the most amount of elements to add new ones to (full ones are removed from the list), but struct1_t s may change the number of elements they have (increment fullest or decrement random only), so I need to be able to update this within this storage quickly. All new struct1_t have 0 elements when added, or (MAX - 1) elements.
However, the challenge here is that I don't know a way to use a linked list, because unfortunately, I'm not able to use malloc. I can only allocate and free entire pages (or multiples) at once.
I think you can do like this, define a struct
struct node{
int data;
struct node *prev;
struct node *next;
};
If you can't use malloc, you can declare a global array
struct node elements[ENOUGH_SPACE];
then use each element of this array like the malloc's result, like
struct node *p = &elements[i];
p->next = ...
p->prev = ...

structure with linked-list memory dump

is there any standard approach which I've missed at school to dump C structure with nested linked lists on disk in reasonable way?
What I don't want to do is:
use protocol-buffers or any other like serializators,
don't want to create JSON, XML or other
I've few ideas:
allocate accurate memory amount (or extend existing one) and manage it by myself, placing list elements in stack like approach using some additional fields to manage relative addresses. When necessary dump block on disk. Having procedures to map block from disk create desirable structure being aware of Byte-order.
push main structure to file, then push List elements, store information about list in the header of a file.
To image this I'll give some more details posting example code:
typedef struct{
int b;
List *next;
}List;
typedef struct{
float b;
List2 *next;
}List2;
typedef struct{
List *head;
List *tail;
} info;
typedef struct{
List2 *head;
List2 *tail;
} info2;
struct data
{
int a;
char t[10];
info first;
info second;
info2 third;
};
cheers
P.
EDIT:
I've extended main structure, seems like previous one haven't indicate the problem fully.
I'm aware that pointers on disk are useless.
Ideas and pseudocode allowed.
There's no neat way to do this, as these will have memory addresses, and the next time it is read in, it will contain memory addresses that could possibly be invalid...the only thing you could do is have a holding area for data to be read/written, let's look at how to write the data to disk based on the contents of the linked list...
struct rwBufferData{
int a;
char t[10];
};
and fill the 'rwBufferData' prior to writing by using memset and memmove
struct rwBufferData rwBuf;
struct data *dataPtr;
memset(&rwBuf, '\0', sizeof(struct rwBufferData));
memmove(&rwBuf, dataPtr, sizeof(struct rwBufferData));
Now you can then write rwBuf to file... I'll leave the reverse operation as an exercise...
I have not understood your problem correctly, but dumping a struct to disk and reading it back reliably has multiple issues.
Most important one is structure padding or byte stuffing. So you would have to take care of that also.
Serialize the data in the order it's held in the linked list, record-style to a file. fwrite is particularly good for this. Be sure to dereference pointers, and be aware of the role endianness plays in this.
Here's some vague pseudocode:
List *list_new();
List *list_add(List *, void *data);
List *list_next(List *);
while (node) {
fwrite(node->data, sizeof(node->data), 1, fp);
node = list_next(node);
}
Rough code for reading back into a live list:
List *node = list_new();
while (true) {
struct data *buf = malloc(sizeof(*buf));
if (1 != fread(buf, sizeof(*buf), 1, fp))
break;
list_add(node, buf);
}
Update0
If you begin to nest more advanced structures such as other linked lists, variable length strings etc., you'll need to provide types and lengths for each record, and a way to nest records within other records.
As an example, if your top level linked list had a data member that was another list, you'd be best to store that member as a nested record, complete with a length, and type field. Alternatively, you could define sentinel records, such as \0 for character strings (an obvious choice), and zeroed blocks for struct data.

Resources