Linked List Assistance [closed] - c

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I'm working on a linked list in C with insert and print functions. However, I am getting a segmentation fault from the insert, and when I try to fix this I end up with one from the print function. Any help would be greatly appreciated.
typedef struct node
{
struct node *next;
double value;
} NodeT, *NodeTP;
int listSize = 0;
int insert(NodeT *firstEle, int value)
{
NodeTP temp;
if((temp = (NodeTP)malloc(sizeof(NodeT))) == NULL)
{
return 0;
}
// first node in the list.
if(listSize == 0)
{
firstEle->value = value;
firstEle->next = NULL;
}
// finds the end node and adds the new node to the list.
else
{
while(temp != NULL)
{
temp = temp->next;
}
temp->value = value;
temp->next = firstEle;
firstEle = temp;
}
listSize++;
return 1;
}
int print(NodeT List)
{
printf("Element: %.2f\n", List.value);
return 1;
}
int main(int argc, char* argv[])
{
// creates the list.
NodeTP list;
if((list = (NodeTP)malloc(sizeof(NodeT))) == NULL)
{
return 0;
}
list = NULL;
insert(list, 5);
print(list[0]);
insert(list, 15);
print(list[1]);
return EXIT_SUCCESS;
}

Print Issue
When it comes to the print statements, you are using an invalid syntax. You created a single pointer and allocated enough memory for that pointer and what it points to. You did not create an array of NodeT elements. As such, the list[x] will not work.
You will need to generate a function that will locate the 'x' element in the list you are making. You could include that in the print function you write. Just change it up to take the int of the element you want:
int print(NodeT head, int element) {}
Don't forget to check your bounds in case the element asked for is outside of your current range.
All you really need to do then is step through the elements to the desired one.
Insert Issue
In your if/else statement, why are you trying to iterate through 'temp'? 'temp' was created in this function and should have no other elements attached to it. You should be iterating through 'firstEle'. You also don't want to set firstEle = temp; as that will over write what was there before and you are now pointing to something else.
One way to simplify this code is to use a head and tail. The head never changes but the tail moves as elements get added. You can have 'insert' return the tail and when you insert a new element, just provide the tail and the new element will be added there, no iteration needed.
Memory Issue
While this will not be major for this program, I would adjust where I malloc my new node till after I have insured that it isn't the first element. Else, you have a block allocated that is never used. Or, if this is the first element to be added, free the block.
And Fred makes a good point. That will cause issues.

Multiple issues (the list is far from complete):
You're missing the include files for malloc() and printf().
You allocate memory in main(), but don't use it.
If you want to modify the list head in insert(), you have to pass a pointer to it.
You check if the memory allocation in insert() succeeds, but don't handle the case that it doesn't - so you can as well just get rid of it.
As you ignore the return values of both insert() and print() you could as well change their return types to void.
While searching for the last element of the list, you overwrite the pointer (temp) to the memory you just allocated.
When you think you've found the last element, you actually make the new element's next point to it and set the first element to point to the new element, which would make it effectively the first and not the last element (if all the other stuff would work...).
You're trying to use array style access with [] for the list. You have to use pointers.
This is a version where I fixed at least the most basic errors in order to make it compile and at least work. It's still far from perfect (or even acceptable), but I tried change as little as possible to make it easier for you to spot the differences and learn what you did wrong and further improve it from there.
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
struct node *next;
double value;
} NodeT, *NodeTP;
int listSize = 0;
int insert(NodeT **firstEle, int value)
{
NodeTP temp, lastEle;
temp = (NodeTP)malloc(sizeof(NodeT));
// first node in the list.
if(listSize == 0)
{
temp->value = value;
temp->next = NULL;
*firstEle = temp;
}
// finds the end node and adds the new node to the list.
else
{
for (lastEle = *firstEle;lastEle->next != NULL;lastEle = lastEle->next);
temp->value = value;
temp->next = NULL;
lastEle->next = temp;
}
listSize++;
return 1;
}
int print(NodeT List)
{
printf("Element: %.2f\n", List.value);
return 1;
}
int main(int argc, char* argv[])
{
// creates the list.
NodeTP list;
list = NULL;
insert(&list, 5);
print(*list);
insert(&list, 15);
print(*list->next);
return EXIT_SUCCESS;
}

Related

Why is the program crashing after assigning a pointer [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 3 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Improve this question
Managing my linked-list is not working. My program just crashes after I set the value "next" to point on previous "head" of the list and after I search and find an element. What can I do?
The program compiles and starts, but it just crashes returning a random address from the memory.
I've tried to change the function to return the pointer of the new "head" instead of being void, but the result is the same.
By verifying where the program stops i found out that it stops doing "new node->next = (*head)" and on previous attempts with the instruction "return last".
I've tried changing almost completely the function just to understand the problem, but even if i pass a pointer to and already allocated list in the main the address does not work and it crashes.
Just to understand whats going on assume that the the program enters for sure in the if with the condition "type_temp=='A'"
This is the main:
#include"devices.h"
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#define LINE_LENGTH 80
#define COMMAND_LENGTH 30
int main(int argc, char** argvs)
{
FILE *fp;
struct Type_A** devices_A = NULL;
struct Type_B** devices_B = NULL;
struct Type_C** devices_C = NULL;
struct Request_Type_C** requests_devices_C = NULL;
int system_power, usable_power,
solar_system_power,solar_system_power_temp;
int id_temp,power_level_temp;
int power_level_normal_temp, power_level_low_temp;
char type_temp;
char file_line[LINE_LENGTH], command[COMMAND_LENGTH];
char *sub_line;
fp = fopen("input1.txt","r");
if(fp == NULL)
{
printf("Error opening the file\n");
return 1;
}
if(fgets(file_line,sizeof(file_line),fp) == NULL)
{
printf("Error reading the first line\n");
return 1;
}
sub_line = strtok(file_line, " ");
strcpy(command,sub_line);
sub_line = strtok(NULL, " ");
system_power = atoi(sub_line);
usable_power = system_power;
while(fgets(file_line,sizeof(file_line),fp) != NULL)
{
sub_line = strtok(file_line, " ");
strcpy(command,sub_line);
if(strcmp(command,"DEVICE_CONNECTED") == 0)
{
sub_line = strtok(NULL, " ");
id_temp = atoi(sub_line);
sub_line = strtok(NULL, " ");
type_temp = *sub_line;
if(type_temp == 'A')
{
sub_line = strtok(NULL, " ");
power_level_normal_temp = atoi(sub_line);
sub_line = strtok(NULL, " ");
power_level_low_temp = atoi(sub_line);
//function with the problem 1
add_device_a(devices_A,id_temp,type_temp,
power_level_normal_temp,power_level_low_temp,0,0);
//function with the problem 2
add_device_a_to_system(devices_A,id_temp,&usable_power);
}
.
.
.
This is the first function with the problem:
void add_device_a(struct Type_A** head, int id, char type,
int power_level_normal, int power_level_low,
int connected, int consume)
{
//allocate the new node
struct Type_A *new_node = (struct Type_A*) malloc(sizeof(struct Type_A));
//put in the data
new_node->id = id;
new_node->type = type;
new_node->power_level_normal = power_level_normal;
new_node->power_level_low = power_level_low;
new_node->connected = connected;
new_node->consume = consume;
//setting the next of the new node
new_node->next = (*head); <-instruction that generates the problem
crashing the program
//move the head to point to the new node
(*head) = new_node;
return;
} //end add_device_a
This is the second function that generates the problem:
int add_device_a_to_system(struct Type_A** head, int id, int* usable_power)
{
struct Type_A *node = find_device_a_by_id(head, id);` <-instruction
that generates the problem
.
.
.
The true function that generates the problem
struct Type_A *find_device_a_by_id(struct Type_A** head, int id)
{
//used for traverse the list
struct Type_A *last = *head;
//check if last is truly the last node
while(last != NULL)
{
//if the id is equal return the pointer to that node
if(last->id == id) {
return last; **<-instruction that makes the program crash**
}
//else keep going with the next
last = last->next;
}
//didn't find an id equal to the one passed ad parameter
return NULL;
}//end of *find_device_a_by_id
Adding an element to the list should add the element on the linked list as first and modify the pointer to that entry.
Finding an element should return a pointer to that specific entry on the linked-list.
You are defining a pointer to a pointer to your struct:
struct Type_A** devices_A = NULL;
Right now it does not point to a valid struct Type_A* as you haven't created one to point it to. So when you pass this into your function add_device_a and it dereferences that variable, you invoke undefined behavior, in this case probably a segfault.
What you probably actually want is to define struct Type_A* devices_A = NULL; And then when you pass it into your function, pass in the address of that pointer:
add_device_a(&devices_A,id_temp,type_temp,
power_level_normal_temp,power_level_low_temp,0,0);
You probably want to declare devices_A as struct Type_A* devices_A = NULL (not as a double pointer), and then call add_device_a() using add_device_a(&devices_A, ....
The way you're doing it is confusing and requires that you allocate space for devices_A, also in this context dereferencing *head when devices_A is NULL is making the program read from address NULL which is undefined behavior and may cause crashes.
You can also see this question about how to manage linked lists properly.

A pointer points to a NULL pointer

code from cs50 harvard course dealing with linked list:
---The problem I do not understand is that when node *ptr points to numbers, which is a null pointer, how can the for loop: (node *ptr = numbers; ptr != NULL) run at all since *numbers = NULL?---
full version of the codes can be found at: https://cdn.cs50.net/2017/fall/lectures/5/src5/list2.c
#include <cs50.h>
#include <stdio.h>
typedef struct node
{
int number;
struct node *next;
}
node;
int main(void)
{
// Memory for numbers
node *numbers = NULL;
// Prompt for numbers (until EOF)
while (true)
{
// Prompt for number
int number = get_int("number: ");
// Check for EOF
if (number == INT_MAX)
{
break;
}
// Check whether number is already in list
bool found = false;
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
{
if (ptr->number == number)
{
found = true;
break;
}
}
The loop is to check for prior existence in the list actively being built. If not there (found was never set true), the remaining inconveniently omitted code adds it to the list.
On initial run, the numbers linked list head pointer is null, signifying an empty list. That doesn't change the algorithm of search + if-not-found-insert whatsoever. It just means the loop is never entered because the bail-case is immediately true. in other words, with numbers being NULL
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
the condition to continue, ptr != NULL is already false, so the body of the for-loop is simply skipped. That leads to the remainder of the code you didn't post, which does the actual insertion. After that insertion, the list now has something, and the next iteration of the outer-while loop will eventually scan the list again after the next prospect value is read. This continues until the outer-while condition is no longer satisfied.
A Different Approach
I have never been fond of the cs50 development strategy, and Harvard's technique for teaching C to entry-level CS students. The cs50 header and lib has caused more transitional confusion to real-world software engineering than one can fathom. Below is an alternative for reading a linked list of values, keeping only unique entries. It may look like a lot, but half of this is inline comments describing what is going on. Some of it will seem trivial, but the search-and-insert methodology is what you should be focusing on. It uses a strategy of pointer-to-pointer that you're likely not familiar with, and this is a good exposure.
Enjoy.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node *next;
};
int main()
{
struct node *numbers = NULL;
int value = 0;
// retrieve list input. stop when we hit
// - anything that doesn't parse as an integer
// - a value less than zero
// - EOF
while (scanf("%d", &value) == 1 && value >= 0)
{
// finds the address-of (not the address-in) the first
// pointer whose node has a value matching ours, or the
// last pointer in the list (which points to NULL).
//
// note the "last" pointer will be the head pointer if
// the list is empty.
struct node **pp = &numbers;
while (*pp && (*pp)->value != value)
pp = &(*pp)->next;
// if we didn't find our value, `pp` holds the address of
// the last pointer in the list. Again, not a pointer to the
// last "node" in the list; rather the last actual "pointer"
// in the list. Think of it as the "next" member of last node,
// and in the case of an empty list, it will be the address of
// the head pointer. *That* is where we will be hanging our
// new node, and since we already know where it goes, there is
// no need to rescan the list again.
if (!*pp)
{
*pp = malloc(sizeof **pp);
if (!*pp)
{
perror("Failed to allocate new node");
exit(EXIT_FAILURE);
}
(*pp)->value = value;
(*pp)->next = NULL;
}
}
// display entire list, single line
for (struct node const *p = numbers; p; p = p->next)
printf("%d ", p->value);
fputc('\n', stdout);
// free the list
while (numbers)
{
struct node *tmp = numbers;
numbers = numbers->next;
free(tmp);
}
return EXIT_SUCCESS;
}
This approach is especially handy when building sorted lists, as it can be altered with just a few changes to do so.
If you examine rest of the code which is also within the while loop, you can see alteration of numbers on the shared link.
if (!found)
{
// Allocate space for number
node *n = malloc(sizeof(node));
if (!n)
{
return 1;
}
// Add number to list
n->number = number;
n->next = NULL;
if (numbers)
{
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
{
if (!ptr->next)
{
ptr->next = n;
break;
}
}
}
else
{
numbers = n;
}
}
Besides, it doesn't hit body of the for loop at first, so your thinking is correct.

C - Segmentation fault - insertion_sort function of linked list

My function insert is not working, after applying some sorting methods that I got at Google (http://teknosrc.com/linked-list-in-c-insertion-sort/).
Firstly, the structures that I'm going to use at it:
// This is the Node , where will be stored the item
struct no
{
Item * item;
struct no *prox;
};
typedef struct no No;
//This is the list, where will have the head node(No)
struct lista
{
char *nomeLista; //This is just a name of the list
No *cabeca; //This is the head node
int tamanho; //This is the amount of items inserted (forgot to implement this)
struct lista *prox; //This is the next list
};
typedef struct lista Lista;
//This is just the main list that will guard all the list of nodes in a linked way. No need to worry about this.
struct vetorListas
{
Lista *cabeca; //head list
int tamanho; //amount of lists
};
typedef struct vetorListas VetorListas;
//This is the item to be inserted
struct item
{
int id; //the ID used for the comparison of sort
char *nome; //just the name of it
};
typedef struct item Item;
In this function, nomeDaList is a string (char *) used to find the list by other function and i is the Item:
void *
insert(void * nomeDaLista, Item * i)
{
Lista * auxLista; //the list
auxLista = idl(nomeDaLista); //the function to get the list by it's name. It works, no worries.
//down here, is the sequence of codes translated to my program (got by the website I showed before)
No * temp = auxLista->cabeca;
No * prev = NULL;
No * ptr;
Item * itemTemp;
itemTemp = temp->item;
ptr = criaNo(i); //this function creates (makes the malloc and all) a node (No) and return the created node.
if(temp == NULL)
{
ptr->prox=NULL;
auxLista->cabeca = ptr;
return auxLista;
}
if(i->id < itemTemp->id)
{
ptr->prox = auxLista->cabeca;
auxLista->cabeca = ptr;
return auxLista;
} else
{
while(temp != NULL)
{
if(i->id > itemTemp->id)
{
prev = temp;
temp = temp->prox;
continue;
} else
{
prev->prox = ptr;
ptr->prox = temp;
return auxLista;
}
}
prev->prox = ptr;
}
}
Please help with this Segmentation fault (core dumped).
You have a check in this line
if(temp == NULL)
which should, and normally would, protect you against segfaults from accessing via NULL pointer.
However, a few lines before, you already dereference the unchecked temp, twice.
itemTemp = temp->item;
and
No * temp = auxLista->cabeca;
You should change the code to make sure that these lines only get executed, if tmp is non-NULL. E.g. split the variable definition and its initialisation and move the init after the check line.
You also receive a pointer from a function criaNo(i) and use it a few lines later, without checking it against NULL.
ptr->prox=NULL;
It is not clear, whether that is guaranteed to be non-NULL. You will have to "rubber-duck" that function, i.e. check in detail, whether it can return NULL.
Here is a nice decription of how to debug (mostly) without a debugger, also explaining "rubber-ducking".
https://ericlippert.com/2014/03/05/how-to-debug-small-programs/
For your problem of not knowing how to use a debugger:
How to debug using gdb?
For your problem of not using an IDE:
Find one, save pain.
My favorite search engine gives (for "free IDE c") my currently used free IDE as first match, the one I am thinking of switching to as third.

Adding nodes inside a linked list using a function

I try to use the CreateRoom function to adding new nodes.
Each time I add a node, I edit the old "lastRoom.next" and make it the current new node's address.
And then I make the current new node's pointer as the new "lastRoom"
I thought this is a good idea and I don't need to return anything. I thought this is good.
However, it doesn't work at all.
I'm really bad at coding and I just learn C. Can anyone help?
struct Room {
int number;
int status;
int luxury;
char occupier[20];
struct Room *next;
};
//I main copy this kind of code from my lecture notes.
//But It's really crappy. This is the only example I can get from the lecture notes
typedef struct Room Room_t;
Room_t *newRoomNode, *ptr, *prev, *temp;
Room_t *firstRoom = NULL, *lastRoom = NULL;
Room_t* CreateRoom(Room_t **first, Room_t **last, int RoomNumber, int type){
Room_t *new = (Room_t *)malloc(sizeof(Room_t));
int *temp;
if (new == NULL)
{
printf("\nMemory was not allocated");
return 0;
}
else
{
//And then I try my way of adding new nodes.
//I don't really understand the example so I make my own
if (*last != NULL)
{
(**last).next = new;
}
new->number = RoomNumber;
new->luxury = type;
new->next = NULL;
*last = new;
if (*first=NULL){
*first=new;
}
}
return 0;
}
void main(){
CreateRoom(&firstRoom, &lastRoom,1,1);
printf("%d",(*firstRoom).number);
}
if (*first=NULL){
*first=new;
}
= is assignment operator. You should use == for comparison.
You shouldn't really bother about the last element. (If you need to traverse the list backward, you have to have a prev member in addition to next.) Now, if you want CreateRoom() to always add a new element at the end of the list, it should first traverse the whole list until it reaches the end of it —which it recognizes because of the NULL pointer— and then assign the new pointer to the place it has reached:
while (*first != NULL)
first = &(*first)->next;
new->number = RoomNumber;
new->luxury = type;
new->next = *first;
*first = new;
Two points are worth being noted:
The assignment *first = new doesn't know if first is firstRoom or the next member of an actual element.
The while loop can be omitted to have new elements inserted at the beginning, or modified so as to have elements sorted the way you want.

Homework, Recursive BST insert function in C

This is homework for my first class in c. It focuses on dynamic allocation in c, in the form of a bst.
I have to have a dynamically allocated BST, recursively implemented. I know that my traversal works correctly, and am having trouble inserting nodes. I only ever have the root node, and every other node seems to be set to NULL. I think that I can't print the rest of the nodes when traversing, because I am trying to access the data member of a NULL struct. My code so far is as follows:
void insert_node(TreeNode** root, int toInsert){
if(*root==NULL){
TreeNode *newnode = (TreeNode *)malloc(sizeof(TreeNode));
newnode->data = toInsert;
newnode->left = NULL;
newnode->right = NULL;
}
else if(toInsert > (*root)->data){ //if toInsert greater than current
struct TreeNode **temp = (TreeNode **)malloc(sizeof(struct TreeNode*));
*temp = (*root)->right;
insert_node(temp, toInsert);
}
else{ //if toInsert is less than or equal to current
struct TreeNode **temp = (TreeNode **)malloc(sizeof(struct TreeNode*));
*temp = (*root)->left;
insert_node(temp, toInsert);
}
}
void build_tree(TreeNode** root, const int elements[], const int count){
if(count > 0){
TreeNode *newroot = (TreeNode *)malloc(sizeof(TreeNode));
newroot->data = elements[0];
newroot->left = NULL;
newroot->right = NULL;
*root = newroot;
for(int i = 1; i < count; i++){
insert_node(root, elements[i]);
}
}
I'm sure it's only one of many problems, but I get segmentation faults on any line that uses "(*root)->data", and I'm not sure why.
As a side note, despite getting segmentation faults for the "(*root)->data" lines, I'm still able to printf "(*root)->data". How is it possible to print the value, but still get a segmentation fault?
It's messy. Some things that might help
1) Don't need to use TreeNode*, pointer to pointer, as argument. Use jsut the TreeNode. (something went wrong here, as it's some feature from the text editor, consider and additional * after each TreeNode in this line)
2) Not a strict rule, but as best practice avoid using the first node of a linked list to store actual values. Use just as the header of your list. Reason is, if you need to delete this node, you don't lose the list. Just a tip
3) In your first function, if *root==NULL, I'd rather make the function fail than adding it to a temporary list (that's being lost in the current code, see that it adds the value to a list that is not being passed outside the function.
4) Well, you are actually making it go to the right if the new value is greater than the node, to the left if it's smaller than the node, but it never stops. See this example:
Suppose you have the list 1->3->4. Now you want to insert 2. What the algorithm will do? keep trying to insert in the 1 node and 3 node, switching between them, but never actually inserting anything.
Solution: as you will build this list bottom up, your list will always be sorted (inf you insert nodes correctly). So you just need to check if the next node is higher, and if it is, insert right where you are.
5) If you're passing a TreeNode *root as argument (on the 2nd function), you shouldn't have to recreate a new list and make root=newlist. Just use the root.
All of this would result in (didn't test, might be some errors):
void insert_node(TreeNode* root, int toInsert){
if(root==NULL){
printf("Error");
return;
}
TreeNode* temp = root; //I just don't like to mess with the original list, rather do this
if(temp->right!=NULL && toInsert > temp->right->data){ //if toInsert greater than next
insert_node(temp->right, toInsert);
}
else{ //if toInsert is less or equal than next node
TreeNode* temp2 = temp->right; //grabbing the list after this node
temp->right=(TreeNode*)malloc(sizeof(TreeNode)); //making room for the new node
temp->right->right=temp2; //putting the pointer to the right position
temp->right->left=temp; //setting the left of the next node to the current
temp->right->data=toInsert;
}
}
void build_tree(TreeNode* root, const int elements[], const int count){
if(count > 0){
for(int i = 0; i < count; i++){
insert_node(root, elements[i]);
}
}
}

Resources