My problem is that, when i try to add a node to my singly linked list for the first time, everything goes expected, but when i want to add another node, my program crashes. Seems like my error is caused by trying to write to 0 address. however i can't seem to find the error in my code. am i using malloc right ?
Here is the code :
typedef struct linkedList
{
int StudentId;
char name[100];
char dep[100];
struct linkedList *next;
} LinkedList;
LinkedList *head = NULL;
LinkedList *current = NULL;
LinkedList *createList(int val, char name[], char dep[])
{
LinkedList *ptr = (LinkedList *)malloc(sizeof(LinkedList));
if (ptr == NULL)
{
printf("Node Creation Failed\n");
return NULL;
}
ptr ->StudentId = val;
strcpy(ptr -> name, name);
strcpy(ptr ->dep, dep);
ptr ->next = NULL;
head = current = ptr;
return ptr;
}
LinkedList *addToList (int val, char name[], char dep[])
{
if (head == NULL)
{
return (createList(val, name, dep));
}
else
{
LinkedList *ptr = (LinkedList *)malloc(sizeof(LinkedList));
if (ptr = NULL)
{
printf("Node Creation Failed\n");
return NULL;
}
ptr -> StudentId = val;
strcpy(ptr ->name, name);
strcpy(ptr ->dep, dep);
ptr -> next = NULL;
current -> next = ptr;
current = ptr;
return ptr;
}
}
in main function:
AddtoList(10,"abc","abc");
calls createList, no problem but
If i use AddtoList again, program crashes, createList and AddtoList are really similar to each other, can't figure out what the problem is.
Change
if (ptr = NULL)
to
if (ptr == NULL)
In your case, ptr is assigned to NULL and expression within if is evaluated to 0. Control goes to ptr -> StudentId = val;. It tries to access write protected memory, hence the crash.
Related
my assignment is to create a linked list and then write a bool function attempts to add a student with given id and name into the given list; if a student with that id is already in the list then return false, otherwise the list is modified and true is returned. Im a beginner and I rarely understand why segmentation faults occur so any help will be appreciated.
here are my structure definitions(provided by prof)
struct snode{
int id;
char * name;
struct snode * next;
};
struct slist{
struct snode * front;
};
here is my bool function
bool insert_student(int id, char name[], struct slist * lst) {
struct snode *head = malloc(sizeof(struct snode));
head = lst->front;
// check if list is empty
if (head != NULL) {
struct snode *node = malloc(sizeof(struct snode));
while (node != NULL) {
// traverse the list to see if student exists in list
if (node->id = id) {
return 0;
}
else {
// if it doesnt exist, add it
struct snode *ins_std = malloc(sizeof(struct snode));
ins_std = node->next;
ins_std->id = id;
ins_std->name = name;
ins_std->next = lst->front;
lst->front = ins_std;
return 1;
}
node = node->next;
}
} // if list is empty
else {
head->next = NULL;
head->name = name;
head->id = id;
return 1;
}
}
main function
int main() {
struct slist *head = create_list();
int id1 = 11001;
int id2 = 11002;
int id3 = 11003;
int id4 = 11004;
int id5 = 11005;
char name1[] = "Dave";
char name2[] = "Ali";
char name3[] = "John";
char name4[] = "Randall";
char name5[] = "Kelly";
assert(insert_student(id1, name1, head) == 1);
insert_student(id2, name2, head);
insert_student(id3, name3, head);
insert_student(id4, name4, head);
insert_student(id5, name5, head);
}
Im a beginner and I rarely understand why segmentation faults occur I suspect you never do at this stage.
struct snode *head = malloc(sizeof(struct snode));
head = lst->front;
Here you allocated some space and save the reference to head, only to be overwritten by lst->front (which could be NULL). These two lines already cause segfault. I think what you are trying to do is to save the reference to the allocated space to lst->front, namely lst->front = head; instead of the other way around.
if(node->id = id){
Common error, use == for equality check.
struct snode *ins_std =malloc(sizeof(struct snode));
ins_std = node->next;
Similar issue to the first code snippet.
Solving the above issues should fix the segfaults and assertion errors. There are also a few logical loopholes in the code, but that is for another story.
As a beginner, it helps to have "working code" to study. Here's a 'stripped down' version of your assignment. Make sure you understand what it does, then gradually add elaborations to build-up toward the entire project.
Programs aren't "typed-in", straight from brain to keyboard. You start off with something simple, then SLOWLY embellish that. Compile (with warnings turned up to the max) often, and test each step along the way.
Best wishes.
struct snode{
int id;
struct snode * next;
};
bool addNode( struct snode **pList, int id ) {
for( struct snode *pSrch = *pList; pSrch; pSrch = pSrch->next )
if( pSrch->id == id )
return false; // already on list...
struct snode *pNew = malloc( sizeof( *pNew ) );
// check of malloc() success omitted
pNew->id = id;
pNew->next = *pList; // PREpending to existing list
*pList = pNew;
return true;
}
int main() {
int ids[] = { 11001, 11002, 11003, 11004, 11005, 11002, 11006, 11007, }; // Notice blooper
const int nIDs = sizeof ids/sizeof ids[0];
struct snode *pList = NULL; // This will be 'buried' as "front"...
for( int i = 0; i < nIDs; i++ ) {
printf( "ID %d ... ", ids[i] );
if( addNode( &pList, ids[i] ) )
printf( "Success\n" );
else
printf( "Failed\n" );
}
for( struct snode *pWalk = pList; pWalk; pWalk = pWalk->next )
printf( "Walking... ID %d\n", pWalk->id );
return 0;
}
There are several mistakes in the code shown.
Here is a cleaned up example.
Within insert_student we:
Immediately check that lst is not NULL. If it is, we immediately return false. Every point in the function afterward we can assume lst is not NULL.
Create a pointer to a node that will point to the last node in the list.
If the front node in the list is not NULL we proceed to check if the node is the last. If it is, store a pointer to it in last. And if the id is already taken, we immediately return false.
Now we allocate a new node, making sure to allocate space for the name (and the null terminator character), and using strcpy to copy the name argument into the memory we've just allocated.
If last was assigned something other than NULL, have its next pointer point to the new node.
If last is still NULL it stands to reason lst->front was NULL. Assign the new node pointer to that pointer.
If execution has reached this point, the insertion has happened. Return true.
A further exercise would be to write a function to free the allocated memory.
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
struct snode {
int id;
char *name;
struct snode *next;
};
struct slist {
struct snode *front;
};
bool insert_student(struct slist *lst, int id, const char *name);
int main() {
struct slist *lst = malloc(sizeof(struct slist));
insert_student(lst, 1, "Bob");
insert_student(lst, 2, "Dave");
for (struct snode *cur = lst->front; cur; cur = cur->next) {
printf("%2d, %s\n", cur->id, cur->name);
}
return 0;
}
bool insert_student(struct slist *lst, int id, const char *name) {
if (!lst) return 0;
struct snode *last = NULL;
if (lst->front) {
for (struct snode *cur = lst->front; cur; cur = cur->next) {
if (cur->next == NULL) last = cur;
if (cur->id == id) return 0;
}
}
struct snode *new_node = malloc(sizeof(struct snode));
new_node->id = id;
new_node->name = malloc(strlen(name) + 1);
strcpy(new_node->name, name);
if (last) {
last->next = new_node;
}
else {
lst->front = new_node;
}
return 1;
}
Output:
1, Bob
2, Dave
I have a weird problem with flushing the entire hash-table.
Data structures are as below:
typedef struct data_entry_{
char data[32];
struct data_entry_ *next;
}data_entry_t;
typedef struct table_entry_{
char hash[32];
struct data_entry_ *next_data;
struct table_entry_ *next_hash;
}table_entry_t;
typedef struct table_{
table_entry_t *next;
}table_t;
In main function, I initialize the table with below function
table_t *init(){
table_t *table = calloc(1, sizeof(table_t));
table_entry_t *node = calloc(1, sizeof(table_entry_t));
node->next_hash = NULL;
node->next_data = NULL;
strcpy(node->hash, "NULL");
table->next = node;
return table;
}
Add data to the table with below function:
int add(table_t *table, char *data){
table_entry_t *head = table->next;
table_entry_t *prev;
char hash[32];
hash_function(data, hash);
if(!strcmp(head->hash, "NULL")){
data_entry_t *item = calloc(1, sizeof(data_entry_t));
strcpy(item->data, data);
item->next = NULL;
strcpy(head->hash, hash);
head->next_data = item;
head->next_hash = NULL;
return 0;
}
while(head){
if(!strcmp(head->hash, hash)){
data_entry_t *temp = head->next_data;
data_entry_t *previous;
while(temp){
if(!strcmp(temp->data, data)){
printf("data exists\n");
return 0;
}
previous = temp;
temp = temp->next;
}
data_entry_t *item = calloc(1, sizeof(data_entry_t));
strcpy(item->data, data);
item->next = NULL;
previous->next = item;
return 0;
}
prev = head;
head = head->next_hash;
}
table_entry_t *pack = calloc(1, sizeof(table_entry_t));
data_entry_t *item = calloc(1, sizeof(data_entry_t));
strcpy(pack->hash, hash);
strcpy(item->data, data);
item->next = NULL;
pack->next_data = item;
prev->next_hash = pack;
return 0;
}
And the problem is with this function:
int flush(table_t *table){
table_entry_t *head = table->next;
table_entry_t *temp;
data_entry_t *current, *previous;
if(head->next_data == NULL){
printf("table is empty\n");
return -1;
}
strcpy(head->hash, "NULL");
while(head){
current = head->next_data;
while(current){
previous = current;
current = current->next;
free(previous);
}
temp = head;
head = head->next_hash;
free(temp);
}
return 0;
}
after calling flush, when I wanna show the table, I expect to see "table is empty" but apparently this function does not free any nodes. I really appreciate if anyone help me.
You expect that a pointer which got freed gets the value NULL.
That however is impossible, because free() only receives the value inside the pointer, not the address, i.e. not pointer to the pointer.
Your code assumes that a freed pointer is NULL here:
if(head->next_data == NULL){
That however will only be the case if you write the NULL value to the pointer.
There is some code which seems similar, strcpy(head->hash, "NULL");, but I trust that you do not expect that to write the non-string value NULL to the pointer.
You can make sure that all pointer which you free afterwards contain NULL, by writing it yourself. Near this free(previous);. It is however necessary to write NULl to the actual pointer in the linked list - and not e.g. to the variable previous. You can use the copy of the pointer stored in that variable to free, but not for overwriting the original.
I have searched a lot, before I ask this, but I can't get this small piece of code to work.
I know that using a global pointer (or variable) is considered a bad practice (instead of passing by reference) but I am forced to use this practice sadly.
What I am trying to do is to make a linked list which consists of nodes (struct with some info), and after every insert() the list is dynamically expanded by one node (unless the element in question already exists, in that case the member name is overwritten).
The pointer next points to the next element in the list (that's where I assign the new node from malloc().
The program compiles correctly and executes with the following output:
retrieve returned: (NULL) at every printf() call
That's why I believe the global pointer (head of the list) is not updated properly
I am sorry for this naive question but I can't seem to find where the assignment/allocation goes wrong, Anyway thanks in advance for your assistance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node{
char *id;
char *name;
struct node *next;
};
struct node* list; //list head
struct node* p; //pointer to list head
char *retrieve(char *id){
if(list == NULL)
return NULL; //list is empty, no element to return.
for(p = list; p != NULL; p = p->next)
if(strcmp(id, p->id) == 0)
return p->name;
return NULL;
}
void insert(char *id, char *name){
int exists = 0;
struct node* temp = NULL;
for(p = list; p != NULL; p = p->next){
if(strcmp(id, p->id) == 0){ //id already exists, overwrite with the new name.
free(p->name);
p->name = strdup(name);
exists = 1;
break;
}
}
if(exists) return;
//insert at the end of the list
temp = malloc(1 * sizeof(struct node));
if(temp == NULL){
printf("memory allocation failed\n");
return;
}
temp->id = strdup(id);
temp->name = strdup(name);
temp->next = NULL;
p = temp;
return;
}
int main(){
struct node* temp = NULL;
p = NULL;
list = NULL;
insert("145a","Jim");
insert("246b","Alice");
insert("322c","Mike");
printf("retrieve returned: %s\n\n", retrieve("145a"));
printf("retrieve returned: %s\n\n", retrieve("246b"));
printf("retrieve returned: %s\n\n", retrieve("322c"));
p = list;
while(p != NULL){ // node deletion starting from first to last element.
free(p->id);
free(p->name);
temp = p;
p = p->next;
free(temp);
}
return 0;
}
void insert(char *id, char *name)
{
struct node *temp = NULL, **pp;
/* Pointer to pointer points to the global */
for(pp = &list; *pp ; pp = &(*pp)->next){
if(strcmp(id, (*pp)->id) ) continue;
free((*pp)->name);
(*pp)->name = strdup(name);
return;
}
//insert at the end of the list
temp = malloc(sizeof *temp);
if(!temp ){
printf("memory allocation failed\n");
return;
}
temp->id = strdup(id);
temp->name = strdup(name);
temp->next = NULL;
*pp = temp;
return;
}
And you can even do without the *temp pointer:
void insert(char *id, char *name)
{
struct node **pp;
for(pp = &list; *pp ; pp = &(*pp)->next){
if(strcmp(id, (*pp)->id) ) continue;
free(p->name);
p->name = strdup(name);
return;
}
// pp now points to the terminal NULL pointer
*pp = malloc(sizeof **pp);
if(!*pp ){
printf("memory allocation failed\n");
return;
}
(*pp)->id = strdup(id);
(*pp)->name = strdup(name);
(*pp)->next = NULL;
return;
}
You never initialize list other than with NULL. In consequence,
char *retrieve(char *id){
if(list == NULL)
return NULL;
always returns NULL.
I keep getting Segmentation Fault (core dumped) run time error and I can't figure out why.
My code:
struct Node
{
void *next;
void *val;
};
typedef struct Node* NodePtr;
struct List
{
NodePtr head;
};
typedef struct List* ListPtr;
ListPtr create()
{
ListPtr ptr = malloc(sizeof(struct List));
return ptr;
}
int insert(ListPtr list, void *obj)
{
NodePtr newObj = malloc(sizeof(struct Node));
//Cast next as a self referencing Node
newObj->next = (NodePtr) newObj->next;
//Point to beginning of list
NodePtr current = list->head;
if(list->head == NULL)
{
newObj->val = obj;
list->head->next = newObj;
newObj->next = NULL;
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
int x = 2;
int *p = &x;
ListPtr thing = create();
insert(thing, p);
return 0;
}
The error is here: list->head->next = newObj after some debugging. I thought I had to allocate memory for list->head->next, but when I added the code in for that it still gave me the same error. Am I casting it wrong or not allocating memory correctly? Any help would be appreciated, thanks!
Just put this together, runs fine.
#include <stdlib.h>
#include <stdio.h>
struct Node {
void *next;
void *val;
};
typedef struct Node* NodePtr;
struct List {
NodePtr head;
};
typedef struct List* ListPtr;
ListPtr CreateList() {
ListPtr ptr = malloc(sizeof(struct List));
return ptr;
}
void Insert(ListPtr list, void *obj) {
// create and initialize new node
NodePtr newObj = malloc(sizeof(struct Node));
newObj->val = obj;
newObj->next = NULL;
//Point to beginning of list
NodePtr curr = list->head;
// Add node to the list
if(curr == NULL) // if no head node, make newObj the head node
{
list->head = newObj;
}
else{ // otherwise traverse the list until you find the last node (the one that points to a null as the next)
while(1) {
if(curr->next != NULL) {
curr = curr -> next;
} else {
curr->next = newObj;
}
list->head = newObj;
newObj->val = obj;
list->head->next = newObj;
newObj->next = NULL;
}
}
}
int main() {
int x = 2;
int *p = &x;
ListPtr thing = CreateList();
Insert(thing, p);
return 0;
}
You check if list->head is NULL and then do some operations with that. Change that to if(list->head != NULL)
{
...
}
At a thought, malloc does not guarantee allocated memory is empty. It's good practice to set all values where they matter after allocation.
list->head is probably not null
also : newObj->next = (NodePtr) newObj->next;
doesn't set to a rational value, it sets to whatever memory was set - were you intending newObj->next = (NodePtr) newObj; ?
list->head should not be referenced if null. list->head->next will only be valid if it's not null.
if you actually want to build a list,
newObj->val = obj;
if (list->head == NULL) { newObj->next = list->head; }
list->head = newObj;
either that or travel down list->head->next chain until next is null, and set that to be newObj->next. If that way then it's possibly a good idea, newObj->next should be set to NULL and not itself.
Might want to figure out how your list will behave - is it circular? does it grow from the head (list->head) or tail (last ->next) ? Do you spot the tail when listObject->next == NULL or when listObject->next == listObject ?
I realize that this answer is mostly stylistic. But I do think that (bad) style and (bad) habits are an (important) part of (bad) programming. Summing it up ...
(in most cases) typedefs are not needed; they just introduce an alias for something that already existed.
[rule of seven] human readers have a limited amount of identifiers ("names") that they can keep track of. This could be 7. Minimising the number of distinct words makes reading easier.
also, the reader has to remember that xPtr and xNode are related (typeof *xPtr === typeof xNode)
when reading source code, keywords and special character tokens (such as operators) don't count as an identifier, since you do not have to remember them. (Syntax-highligting helps, too)
if there is only one way of expressing your program, there is no possibility for errors like iPtr *p; p = (qPtr) malloc (sizeof xNode);
creating yet another struct (+typedefs for it), just to accomodate a root pointer will clobber up your mental namespace even more.
Now a rework of the (intended) code:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *next;
void *payload;
};
struct node *root=NULL;
void initialize() { /* nothing .... */ }
int insert(struct node **pp, void *pv) {
struct node *p;
p = malloc(sizeof *p);
if (!p) { /* handle error */ return -1; }
p->payload = pv;
p->next = *pp;
*pp = p;
return 1; /* inserted one element */
}
int main(void)
{
int i;
i=666;
/* note: this function call will pass a pointer to a local variable `i`
** to the insert() function, which will remember it.
** This is generally a bad idea, to say the least.
*/
insert( &root, &i);
return 0;
}
I'm having a problem with inserting a node at the end of a linked list. It's not being executed when the start node is not null and I don't understand the problem. Please help me out here. The function is called second time but is not going to the else block.
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info *tokenlist;
token_Info* insert_at_end( token_Info *list,char *name)
{
printf("token identified \t");
token_Info *new_node;
token_Info *temp,*start;
start = list ;
char *tempname ;
tempname = name;
new_node= malloc(sizeof(token_Info));
new_node->token = malloc(sizeof(strlen(tempname)+1));
strcpy(new_node->token,tempname);
new_node->next= NULL;
// printf("%d",strlen(tempname));
if(new_node == NULL){
printf("nFailed to Allocate Memory");
}
if(start==NULL)
{
start=new_node;
return start;
}
else
{
printf("anvesh");
temp = start;
while(temp->next != NULL)
{
temp = temp ->next;
}
temp->next = new_node;
return temp;
}
}
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
UPDATE
I found two bugs, the first was the head of the list was not being returned when appending the list. The other in the memory allocation for the token string which incorrectly used sizeof.
I repositioned the test of the malloc() return value, and added a second one. I removed several unnecessary temporary variables that were cluttering the code. I added two functions, show_list() and free_list(). Finally, remember that the value string field is still uninitialised.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct token_Info
{
int linenumber;
char* token;
char value[200];
struct token_Info* next;
} token_Info;
token_Info* insert_at_end( token_Info *list, char *name)
{
token_Info *new_node, *temp;
new_node= malloc(sizeof(token_Info));
if(new_node == NULL){ // repositioned
printf("\nFailed to allocate node memory\n");
exit(1); // added
}
new_node->token = malloc(strlen(name)+1); // removed sizeof
if(new_node->token == NULL){ // added
printf("\nFailed to allocate token memory\n");
exit(1);
}
strcpy(new_node->token, name);
new_node->next= NULL;
if(list==NULL)
return new_node;
// append
temp = list;
while(temp->next != NULL)
temp = temp->next;
temp->next = new_node;
return list; // original head
}
void free_list( token_Info *list)
{
token_Info *temp;
while (list) {
temp = list->next;
free(list->token);
free(list);
list = temp;
}
}
void show_list( token_Info *list)
{
printf ("\nCurrent list:\n");
while (list) {
printf ("%s\n", list->token);
list = list->next;
}
}
int main(int argc, char **argv)
{
token_Info *tokenlist = NULL;
tokenlist = insert_at_end(tokenlist, "TK_BEGIN");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_SECOND");
show_list(tokenlist);
tokenlist = insert_at_end(tokenlist, "TK_FINAL");
show_list(tokenlist);
free_list(tokenlist);
return 0;
}
Program output:
Current list:
TK_BEGIN
Current list:
TK_BEGIN
TK_SECOND
Current list:
TK_BEGIN
TK_SECOND
TK_FINAL
The question could also be whether you want tokenlist to be a running end of the list, or remain at the start.
As of right now, your first call:
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
has tokenlist being the only node in the list.
The second call tokenlist = insert_at_end(tokenlist,"TK_BEGIN1"); returns 'temp' which happens to also be the 'TK_BEGIN' node, ( ie, the first node )
If you want the return value to be the last element, you would return new_node instead of temp. If you want to retain the start, you would return start;
All that said:
The calls to it are not part of any function,
I just ran it with the calls in main and got this output:
int main(void){
tokenlist = insert_at_end(tokenlist,"TK_BEGIN");
tokenlist = insert_at_end(tokenlist,"TK_BEGIN1");
return 0;
}
$> ./a.out
token identified token identified anvesh