Storing data inside structs (Linked List) - c

Hi guys I'm learning C and there are some issues that I can't solve.
first of all, this are my data structure:
struct user_node {
void *name;
struct user_node *next;
struct msg_node *msgnext;
};
struct msg_node {
void *sender;
void *receiver;
void *title;
void *content;
struct msg_node *msgnext;
};
struct user_node *user_database = NULL;
The idea is that a user may have one or more messages.
Well I can create and delete users but I'm having problem storing messages, for example here:
The purpose of this function is to put temp as a message inside my data structure for a given user that we find in the message itself. (temp is already msg_node with data which I take from another function)
void sendMsg(struct msg_node* temp) {
//if list is empty
if (user_database == NULL) {
printf("There aren't users on the system.\n\n");
return;
}
struct user_node** ptr = &user_database;
while (*ptr) {
if (strncmp((*ptr)->name, (temp)->receiver, strlen(temp-
>receiver)) == 0) {
temp->msgnext = &user_database->msgnext;
user_database->msgnext = temp;
return;
}
ptr = &(*ptr)->next;
}
printf("User not found on the system\n\n");
return;
}
I know that the code is wrong but I been messing arround with this since yesterday and I can't figure it , may someone help me?
Thanks in advance

You can insert a node at the front of a linked list by sett ing the new node's next pointer to the list's head and then setting the lis's head to the new node. This works even for an empty list, when the list's head is NULL.
You've got this almost right, but the List's head is the one associated with the current user, not with the user list's head, i.e. the first user in the database.
The following code should do what you want:
int sendMsg(struct msg_node *msg)
{
struct user_node *user = user_database;
if (user == NULL) {
printf("There aren't users on the system.\n");
return -1;
}
while (user) {
if (strcmp(ptr->name, msg->receiver) == 0) {
msg->msgnext = user->msgnext;
user->msgnext = msg;
return 0;
}
user = user->next;
}
printf("User '%s' not found on the system.\n", msg->receiver);
return -1;
}
Notes:
I've renamed the pointers from the rather nondescript temp and ptr to the more descriptive msg and user.
I've made the function return a success code: 0 for success and −1 for failure.
strncmp will compare only a certain number of characters. I've changed this to strcmp, so that the users Paul and Pauline are considered different.
There's no need to make the traversing pointer a pointer to pointer to node. That technique is useful, but only when you want to insert or delete nodes. Inserting at the front is a special case where you won't need it. (And you insert a message, not a user, so if you wanted to insert the message somewhere else than at the front, you could iterate through the sub-list with a pointer to pointer to message node.)

Related

Understanding function called by reference on lists

I'd like to know why the code given below works well.
It should,recursively, given a list, put a -1 in front of the even numbers.
Ex. Input : 4->7->1->10->NULL Output : -1->10->1->7->-1->4->NULL
I don't understand how the function,being recursive, could keep track of the eventual *head,which is changed every time , due to the fact that the function called itself by reference.
In the end what I'm not getting is how the output could be correct given those (to me) misconception of how a recursive function by reference works.
Here's the code with the following declarations :
typedef struct El {
int info;
struct El *next;}ElementoLista;
typedef ElementoLista *ListaDiElementi;
void inserisci(ListaDiElementi *head) {
if((*head) != NULL && ((*head)->info)%2 == 0) {
inserisci(&(*head)->next);
ListaDiElementi aux = malloc(sizeof(ElementoLista));
aux->info = -1;
aux->next = *head;
*head = aux;
} else {
if((*head) != NULL) {
inserisci(&(*head)->next);
}
}
}
I think your troubles with the code is due to the code being "a bit poorly" written, i.e. less clear than it could be. I see three issues.
1) "typedef of pointer" makes it hard to understand what types are involved. Especially when it's not clear that a specific type is a pointer. A name like ListaDiElementi is not (at least not to me) making it clear that this is a pointer. A better name could be ElementoLista_ptr but overall it's better to avoid pointer typedef.
2) The function argument is named head. This is confusing because we normally think of head as the pointer to the first element of a list. But that's not what is going on here. The argument is really a double pointer and further it does not point to the first element. It points to next pointers.
3) The if constructs hides logic of the program.
So let's rewrite the code to get rid of the above while still keeping the same functionality:
typedef struct El {
int info;
struct El *next;
} ElementoLista;
void inserisci(ElementoLista **pNext) {
if ((*pNext) == NULL) return;
inserisci(&(*pNext)->next);
if(((*pNext)->info)%2 == 0) {
ElementoLista* aux = malloc(sizeof(ElementoLista));
aux->info = -1;
aux->next = *pNext;
*pNext = aux;
}
}
With this code it's easier to see that the code keeps calling it self recursively until it reaches the end. On the way back, i.e. as the function calls return, the code checks whether it needs to insert a "-1" node.
The same code with some comments to explain:
typedef struct El {
int info;
struct El *next;} ElementoLista;
// pNext is a pointer to the "next pointer" of the previous node
// Consequently (*pNext) is a pointer to the current node
void inserisci(ElementoLista **pNext) {
// Return if we have reached the end of the list
if ((*pNext) == NULL) return;
// Keep calling until the end is reached
inserisci(&(*pNext)->next);
// On the "way back" (i.e. as the recursive calls return) check
// if we need to insert a "-1" node
if(((*pNext)->info)%2 == 0) {
// We need a new node
ElementoLista* aux = malloc(sizeof(ElementoLista));
aux->info = -1;
// Make the new node point to current node
aux->next = *pNext;
// Update the next pointer to point to the new node
*pNext = aux;
}
}
When you understand this simplified version of the code, you should also understand the original version.

Creating and displaying linear linked list in C(Recursively)

I'm trying to creating linear linked list recursively with c language,
but keep sticking from here and the code is not working with the error "Linker Tools Error LNK2019". Sadly i can't understand what's the matter. Here is my code.
Thanks for your big help in advance.
#include <stdio.h>
#include <stdlib.h>
struct node
{
char num; //Data of the node
struct node *nextptr; //Address of the next node
};
typedef struct node element;
typedef element *link;
link head;
void displayList(); // function to display the list
int main()
{
char s[] = "abc";
link stol(s);
{
link head;
if (s[0] == '\0')return(NULL);
else {
head = (link)malloc(sizeof(element));
head->num = s[0];
head->nextptr = stol(s + 1);
return(head);
}
}
printf("\n\n Linked List : To create and display Singly Linked List :\n");
printf("-------------------------------------------------------------\n");
displayList();
return 0;
}
void displayList()
{
link tmp;
if (head == NULL)
{
printf(" List is empty.");
}
else
{
tmp = head;
while (tmp != NULL)
{
printf(" Data = %d\n", tmp->num); // prints the data of current node
tmp = tmp->nextptr; // advances the position of current node
}
}
}
You redefine a link object called head in your main() function. It hides the global head variable.
Removing the definition inside main would fix your problem, but you should consider passing a link* as a parameter to your displayList function in any case.
I've just noticed this statement return(head); in main(). You program exits prematurely as a result as well.
Everytime I look at your app, I find more issues. If I were you, I'd start by creating a function that adds a node to the list. It's much easier to add new nodes to the front of the list, so you should try that first. Try adding to the tail once you get this running. Adding to the tail is very similar, but you have to 'walkthe list first to get to the last element, exactly as you already do indisplayList()` Another way is keeping the address of the last node* you've added to the list. Like I said, it adds a bit of complexity, so get it working with addToHead first.
void addToHead(link* l, node* n)
{
n->nextptr = l->nextptr;
l->nextptr = n;
}
in your main, you can allocate one new node at a time, as you already do with malloc(). Initialize its contents num with an integer, and let addToHead deal with the pointer stuff. Your use of pointers is terrible, but lists are quite easy, and addToList pretty much shows what can and what should be put in pointers - namely other pointers.
You can remove almost everything in main() before the first printf. You'll have to
start loop:
write a prompt so the user knows what to do using printf()
read input from user using scanf("%d", &n), or equivalent.
break from the loop if user enters a negative value.
malloc() a new node
set its data num = n
call addToHead to add the node.
Loop until user enters an empty string, or -1.
That should take about 8 to 10 lines of code. if in doubt, you will easily find documentation on scanf, with google or on http://en.cppreference.com/w/c.

Deleting Linked LIst in C

I just stuck with the problem couple of hours, trying to find where my code breaks. I know how to delete linked list but something doesn't work.
First it is a very simple struct with a dataype of int and 2 struct *next and *prev.
struct _list_{
struct _list_ *next;
struct _list_ *prev;
float distance;
}
Now i am making a push_front function and it works great. I get the result that i am looking for. But now i am making pop_front function and something is missing.
The function should return the distance and then remove that list from the linked list but i can't make it do it.
here is the code that i wrote
int pop_front(list** header)
{
float number = (*header)->data;
list *head = *header;
list *remove = head;
// This should check if the pointer is pointing at the first element
while (head->prev != NULL) {
head = head->prev;
}
if (head) {
head = head->next;
free(remove);
remove = head;
remove->prev = NULL;
//if i remove the code below then i get this error
//*** Error in `./double_ended_queue.out': double free or
//corruption (fasttop): 0x0000000001d5a050 ***
//Pop up: 3 pointer: 3 Aborted (core dumped)
*header = *remove;
//And with this code i get a Segmentation fault (core dumped
return number;
}
return 0;
}
Any help would be great, thank you.
P.S. checked all the linked list question here and none helped.
Where are you all getting this homework from? The API sux. Here, someone else did have almost the same homework (link pointing to my answer, which has many issues left): Pointer Dequeue - pointer training
Anyways:
Do you want to return int or float? The element data is type float, your variable "number" too, but your function returns int.
int pop_front(list** header)
{
float number = (*header)->data;
so, here you get the value of the element you're trying to remove, but then ...
list *head = *header;
list *remove = head;
// This should check if the pointer is pointing at the first element
while (head->prev != NULL) {
head = head->prev;
}
... you actually SEARCH for the element to remove.
Obviously, you have to do it the other way round:
int pop_front(list** header)
{
list * head = *header;
while (head->prev) head = head->prev;
now, you should check, weather you need to adjust the *header pointer (and do it right away):
if (*header == head) {
*header = head->next;
}
the only thing to do now is to remove the object from the list, get it's value and free it's memory before return.
head->next->prev = NULL;
float retval = head->data;
free(head);
return retval;
}
As exercise left to you: Make sure, that an empty list doesn't crash ;)
/edit: This will also crash for removal of the last element, so you have two exercises left ;)

Adding Nodes in Linked List

I am trying to add users to a linked list. I have two structs and a method to add called add_friend that sets up the addition of the node. The program does not ask for user input but passes the info through parameters in the add_friend method: In addition to adding the node (user) to the list I have to check if user already exists. I am getting an error when I try to compare string to see if the user exists. Any help? Unfortunately C is my weakest programming language, Im having a hard time understanding the pointers
struct UserAccountNode {
struct UserAccount* content;
char circle;
struct UserAccountNode* next;
} *head = NULL;
struct UserAccount {
char username[255];
char lastnm [256];
char firstnm[256];
char password[256];
char gender;
int phone;
struct Post* post_list;
struct UserAccountNode* friend_list;
};
int add_friend(UserAccount* user, char Circle, UserAccount* Friend) {
struct UserAccountNode* friend_list;
friend_list = (struct UserAccountNode* ) malloc (sizeof(struct UserAccountNode));
while (friend_list != NULL)
if (stricmp(Circle, head->friend_list) == 0) {
friend_list -> next = head;
head = friend_list;
} else {
printf("%d, User Already Exists", Friend);
}
return 0;
}
The code does not compare strings. It compares char - Circle - with UserAccountNode* friend_list. But stricmp requires both arguments to be const char *. You have to do a loop through all items in friend_list and compare every username with a given one.
Another issue: you allocate memory for UserAccountNode but do not allocate memory for its internal field UserAccount* content. It may crash the application when you try to read the data.
type of Circle is char not char*,
type of head->friend_list is UserAccountNode*.
So, you try to compare non-string objects as strings here:
if (stricmp(Circle, head->friend_list) == 0)
I think your program can't be compiled.

unable to access memory 0X.... C program (Ubuntu 12.10)

Purpose of code:
TO maintain a unique element link list...UFID is the keyword for unique
Structure declaration:
struct sharedFiles
{
char UFID[50];
int valid; //valid 1 if someone have this file in write mode
int shared; //no of user's reading this file
struct sharedFiles *next; //pointer to next node
}*sfstart,*sfend; //sfstart points to the first node of linked list and efend to the last node of linked list so that it will be easy to just insert at the end without traversing the linked list
Error Description:
The below code gives segmentation fault when I invoking it 2nd time.
I tried to debug with GDB and it says unable to access the location at line
if(strcmp(sftemp->UFID,ufid)==0)
In the above line it is unable to access sftemp->UFID
/*Function code*/
int addShareList(char *ufid,int mode) //mode=0 (read) and mode=1 (Write request)
{
struct sharedFiles *sftemp,*newnode;
sftemp=sfstart;
if(sfstart==NULL) //if list is empty add first node
{
sfstart=(struct sharedFiles *) malloc(sizeof(struct sharedFiles));
strcpy(sfstart->UFID,ufid);
sfstart->valid=mode;
sfstart->shared=1;
sfstart->next=NULL;
sfend=sfstart; //this node will also be last node of Linked list
return 0;
}
else //if list is not empty
{
while(sftemp->next != NULL) //traverse till last node
{
if(strcmp(sftemp->UFID,ufid)==0)
{
//here if same node found some manupulation to the struct variables
}
sftemp=sftemp->next;
} //while
if(sftemp->next==NULL) //procvess last node
{
if(strcmp(sftemp->UFID,ufid)!=0) //if last node not same add node at the end of Linked list
{
newnode=(struct sharedFiles *) malloc(sizeof(struct sharedFiles));
strcpy(newnode->UFID,ufid);
newnode->valid=mode;
newnode->shared=1;
newnode->next=NULL;
sftemp->next=newnode;
sfend=newnode;
return 0;
}
else //if last node is same
{
//some manipulations to struct variables
}
} //if
}
return -1;
}//addShareList
The above code works fine for inserting first element.When I invoke the same function for inserting second node in the linked list it unable to access the first node while comarision
in the line if(strcmp(sftemp->UFID,ufid)==0). Hope now the purpose of code is clear.
Thanks in advance..
In the while you check if sftemp!=NULL so we can be sure that in the second iteration, after line sftemp=sftemp->next; the pointer contain allocated memory.
But, since I don't know how the list it structured, I can't be sure that the content contains another node of sharedFiles type, it could contain an end-list node which not contains UFID attribute.
So, check in your list how to control if the list is finished.
Another solution can be to change your check this way:
while(sftemp->next!=NULL)
...
if(sftemp->next==NULL) {
//add the node in the right way, consider the end-list node
}
EDIT:
Furthermore, change in the first if the line sftemp->next = NULL; to sfnext->next = NULL;.
And be sure to initialize stnext = NULL.
EDIT 2:
Now that you post struct declaration I still cannot see when you initialize sfstart. Try to do this:
Structure declaration:
struct sharedFiles
{
char UFID[50];
int valid; //valid 1 if someone have this file in write mode
int shared; //no of user's reading this file
struct sharedFiles *next; //pointer to next node
}*sfstart = NULL,*sfend;
Normally the answer for this is that the pointer is NULL, which in your case means malloc has failed because you're out of memory - you really should be checking the return value.
The most likely cause for your problem is that you have corrupted the heap, so that sftemp no longer points to a valid memory address. Check what it's value is that might give you some more clues.

Resources