I want to create a function that adds an element to the end of a linked list. It also has to return 0 if the element was added successfully, or a 1 if memory could not allocated/saved to for the element.
The question is, how do I know if the memory was allocated successfully or if the element was added successfully? This is the code:
int push_back(pos_t *head, int new_value) {
pos_t *temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
pos_t *temp1 = (pos_t *)malloc(sizeof(pos_t));
temp1->data = new_value;
temp1->next = NULL;
temp = temp1;
}
You need to add the following code
if (temp1 == NULL) { return 1; }
because malloc is defined to either return a pointer to the allocated memory, or
if the size is zero, return NULL.
on error, return NULL.
You can control that you don't request a size of zero, so if you used a positive size, and malloc returned NULL, you can deduce an error occurred.
Many systems have "manuals" installed. If you are using a Linux system, the command "man malloc" will pull up the manual page for malloc. If you are working on a Windows system, a web search for the manual for malloc will give you enough detail to handle the details.
The function has a shortcoming: it cannot be used to allocate the first node in the list, ie if the list is empty.
The prototype should be changed to
int push_back(pos_t **headp, int new_value);
passing the address of the list pointer instead of its value.
Testing for malloc() failure is simple: juts compare the returned pointer to NULL or 0.
Here is the corresponding code:
int push_back(pos_t **headp, int new_value) {
pos_t *temp = *headp;
pos_t *temp1 = malloc(sizeof(pos_t));
if (temp1 == NULL) { // allocation failure
return 1;
}
temp1->data = new_value;
temp1->next = NULL;
if (temp == NULL) { // empty list
*headp = temp1;
} else {
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = temp1; // append node to the end of the list
}
return 0;
}
Related
Is this a right way to do a linked list ? I am having a problem in a big school project and now i want to make sure that this is true.
void addnode(int a){
struct house* tmp = houses[i].next;
while (tmp != NULL) {
tmp = tmp->next;
}
tmp = (struct house*)malloc(sizeof(struct house));
tmp->id=a;
tmp->next=NULL;
}
i figured out that the error can be in other parts of the code. Now i will share the parts i suspect i hope you can help me.
houses[i] is an array of linked lists. if houses[i].id==-1 it is empty
struct house get_house_byid(int id) {
for (int i = 0; i < 1000; i++) {
if (houses[i].id != -1) {
if (houses[i].id == id) {
return houses[i];
}
if (houses[i].next != NULL) {
struct house* tmp = houses[i].next;
while (tmp != NULL) {
if (tmp->id == id) {
return *tmp;
}
tmp = tmp->next;
}
}
}
}
struct house housep;
housep.id = -1;
return housep;//if it cant find that id it returns housep
}
There may be other issues with your code that is not shown, but there are issues with addnode:
addnode does not set the head of the list (i.e. houses[i].next).
Thus, the newly added node is never connected to anything [and is a memory leak].
Ignoring the [obvious] typo/syntax error: void addnode{int a} instead of void addnode(int a).
The loop on tmp discards the pointer to the tail of the list. We need a separate variable (e.g. prev).
Note that i is global. That's fine, but the function would be cleaner if i was an argument to addnode instead.
Don't cast the return of malloc: Do I cast the result of malloc?
Here's is some refactored code. It is annotated:
void
addnode(int i,int a)
{
struct house *tmp;
struct house *prev;
// find the tail of the list
prev = NULL;
for (tmp = houses[i].next; tmp != NULL; tmp = tmp->next)
prev = tmp;
// allocate the new node
tmp = malloc(sizeof(*tmp));
tmp->id = a;
tmp->next = NULL;
// append to the tail of the [non-empty] list
if (prev != NULL)
prev->next = tmp;
// add to front of the empty list
else
houses[i].next = tmp;
}
Each node is 8 bytes and I allocate 3 in my program (8*3 = 24) so I assume thats the memory im losing.
This is the valgrind error
24 (8 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
==2381== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==2381== by 0x8048598: mh_alloc (in /media/sf_Z_DRIVE/comp2401a4/a4)
==2381== by 0x8048857: main (in /media/sf_Z_DRIVE/comp2401a4/a4)
this is the BlockType which is the data the nodes carry.
typedef struct {
int rsv;
void *addr;
int size;
char tag[MAX_STR];
} BlockType;
This is where valgrind says im losing the data.
void *mh_alloc(HeapType *heap, int n, char *label){ //this is the allocation function
BlockType *blk;
blk = (BlockType *)malloc(sizeof(BlockType));
blk->rsv = C_TRUE; //set block to reserved
blk->addr = blk; //set the address to keep track of where the block is stored in memory
blk->size = n; // set the size of the block
strcpy(blk->tag, label); //add the name of the block
Node *temp2 = malloc(sizeof(struct Node));
temp2->block = blk;
temp2->next = NULL;
if (heap->head == NULL) {
heap->head = temp2;
}
else{
struct Node *temp = heap->head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = temp2;
}
return blk; //we return blk because we assign pointers to such blocks in the main function.
}
This the function called at the end to free all blocks and nodes ->
void mh_collect(HeapType *heap){ //function to unreserve all elements in the array, and free each address
struct Node *temp = heap->head;
struct Node *prev = NULL;
if (temp->next == NULL){
printf("Only the head left");
temp->block->rsv = C_FALSE;
return;
}
while(temp != NULL){
temp->block->rsv = C_FALSE;
free(temp->block->addr);
temp = temp->next;
}
}
Edit: (The original question was modified)
This code looks wrong:
while(temp != NULL){
temp->block->rsv = C_FALSE;
free(temp->block->addr);
temp = temp->next;
}
In your loop, you don't free the node temp itself. Note that this doesn't "leak" any memory, but it does leave the memory hanging around. You may want to consider something like this:
while(temp != NULL){
Node *next = temp->next;
temp->block->rsv = C_FALSE; // Seems useless because you are freeing it.
free(temp->block); // Note: temp->block->addr == temp->block
free(temp);
temp = next;
}
Also, if you ever assign to block->addr other than what you showed above, then that could be the cause of your leak. I'm not sure what the use of block->addr is, but I would suggest removing it unless it serves some other purpose.
I need to create the push method for a program that push an element into a stack. I have created this typedef:
typedef struct node{
int value;
struct node *next;
} Node;
With this snippet of code in my main:
Node *stackptr;
stackptr = NULL;
This is where I have a problem and am not sure exactly what is going on - In my push method im not sure if I am returning the updated pointer to the top of the stack. Im suppose to check if it is empty as well but I am going to get to that last. Here is the push() function:
void push(Node *stkptr, int i){
Node *temp;
temp = malloc(sizeof(Node));
temp->value = i;
temp->next = *stkptr;
return *stkptr = temp;
}
Hope this makes some sort of sense what I am trying to get across. Thanks for any advice you are able to give me. Hope all is well.
Last I am in need of fixing my int pop() function! I have to return the value of the node that was popped. I believe I am almost there - my compiler is still throwing errors. This is what I have so far:
int pop(Node** stkptr){
Node *temp;
temp = malloc(sizeof(Node));
if((*stkptr) == NULL){
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else{
temp = *stkptr;
stkptr = *temp;
}
return stkptr;
free(temp);
}
However, the compiler is throwing the error:
incompatible types when assigning to type ‘struct Node **’ from type ‘Node’
warning: return makes integer from pointer without a cast
Can someone please help me fix my problem! Thanks!
There must be a lot of duplicates for this (for example, Implementing stack with linked list in C from the related questions section), but basically, you need to pass a pointer to a pointer into the function:
void push(Node **stkptr, int i)
{
Node *temp;
temp = malloc(sizeof(Node));
temp->value = i;
temp->next = *stkptr;
*stkptr = temp;
}
You also can't return a value from a function that returns void. You should also check that the memory allocation worked.
You'd call this from, for example, your main program:
Node *stack = NULL;
int i;
while (get_an_integer(&i) != EOF)
push(&stack, i);
where get_an_integer() is a hypothetical function that reads an integer from somewhere and assigns it to i, while returning a status (0 — got an integer; EOF — didn't get an integer).
An alternative design returns the new head of the stack from the function:
Node *push(Node *stkptr, int i)
{
Node *node;
node = malloc(sizeof(Node));
node->value = i;
node->next = stkptr;
return node;
}
with calling sequence:
Node *stack = NULL;
int i;
while (get_an_integer(&i) != EOF)
stack = push(stack, i);
A question about pop()
The pop() function appears to remove and destroy the first item on the stack, rather than returning it. However, there are a number of flaws in it, such as it allocates space, then overwrites the pointer with information from the stack, then returns before freeing the data. So, assuming that the demolition job is required, the code should be:
int pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp == NULL)
{
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else
{
*stkptr = temp->next;
free(temp); // Or call the function to deallocate a Node
return 1;
}
}
This now returns 1 when successful and 0 when the stack was empty. Alternatively, if you wanted the value from the top of the stack returned rather than freed, then:
Node *pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp == NULL)
{
fprintf(stderr, "The stack is empty. Pop is not allowed\n");
return 0;
}
else
{
*stkptr = temp->next;
return temp;
}
}
Or, since you are told by the return value whether there was anything to pop, and printing in a library function can be objectionable, maybe even:
Node *pop(Node **stkptr)
{
assert(stkptr != 0);
Node *temp = *stkptr;
if (temp != NULL)
*stkptr = temp->next;
return temp;
}
Warning: none of the code has been submitted to a compiler for verification.
I am trying to write a singly-linked list in C. So far, I just get segmentation faults.
I am probably setting the pointers wrong, but I just couldn't figure how to do it correctly.
The list should be used for "processors" sorted from highest priority (at the beginning of the list) to lowest priority (at the end of the list). Head should point to the first element, but somehow I am doing it wrong.
First of all here is the code:
struct process {
int id;
int priority;
struct process *next;
}
struct process *head = NULL;
void insert(int id, int priority) {
struct process * element = (struct process *) malloc(sizeof(struct process));
element->id = id;
element->priority = priority;
while(head->next->priority >= priority)
head = head->next;
element->next = head->next;
head->next = element;
// I put here a printf to result, which leads to segmenatition fault
// printf("%d %d\n", element->id, element->priority);
}
/* This function should return and remove element with the highest priority */
int pop() {
struct process * element = head->next;
if(element == NULL)
return -1;
head->next = element->next;
free(element);
return element->id;
}
/* This function should remove a element with a given id */
void popId(int id) {
struct process *ptr = head;
struct process *tmp = NULL;
while(prt != NULL) {
if(ptr->id == id) {
ptr->next = ptr->next->next;
tmp = ptr->next;
} else {
prt = ptr->next;
}
}
free(tmp);
}
Unfortunately, I could not try out pop() and popId() due to the segmentation fault.
May anyone tell me what I am doing wrong?
EDIT: Now, I edited the insert function. It looks like this:
void insert(int id, int priority) {
struct process * element = (struct process *) malloc(sizeof(struct process));
struct process * temp = head;
element->id = id;
element->priority = priority;
if(head == NULL) {
head = element; // edited due to Dukeling
element->next = NULL;
} else {
while(temp->next != NULL && temp->next->priority >= priority)
temp = temp->next;
element->next = head->next;
head->next = element;
}
// I put here a printf to result, which leads to segmenatition fault
// printf("%d %d\n", element->id, element->priority);
}
But I still get segmentation fault for pop() and popId(). What did I miss here?
You don't check if head is NULL in insert.
You actually don't check if head is NULL in any function. You should, unless you want to put some dummy element on head, to simplify the code.
For insert:
About these lines:
while(head->next->priority >= priority)
head = head->next;
If head is NULL, that's not going to work. This may not actually be a problem if head can never be NULL for whichever reason (e.g. it has a dummy element as gruszczy mentioned).
You're changing head, thus you're getting rid of the first few elements every time you insert. You probably need a temp variable.
You need to also have a NULL check in case you reach the end of the list.
So, we get:
struct process *temp = head;
while (temp->next != NULL && temp->next->priority >= priority)
temp = temp->next;
For pop:
If the first element isn't a dummy element, then you should be returning the ID of head, not head->next (and you were trying to return a value of an already freed variable - this is undefined behaviour).
if (head == NULL)
return -1;
int id = head->id;
struct process *temp = head;
head = head->next;
free(temp);
return id;
For popId:
You're checking ptr's ID, but, if it's the one we're looking for, you're removing the next element rather than ptr. You should be checking the next one's ID.
head == NULL would again need to be a special case.
The free should be in the if-statement. If it isn't, you need to cater for it not being found or finding multiple elements with the same ID.
You should break out of the loop in the if-statement if there can only be one element with that ID, or you want to only remove the first such element.
I'll leave it to you to fix, but here's a version using double-pointers.
void popId(int id)
{
struct process **ptr = &head;
while (*ptr != NULL)
{
if ((*ptr)->id == id)
{
struct process *temp = *ptr;
*ptr = (*ptr)->next;
free(temp);
}
else
{
prt = &(*ptr)->next;
}
}
}
Note that the above code doesn't break out of the loop in the if-statement. This can be added if you're guaranteed to only have one element with some given ID in the list, or you want to just delete the first such element.
Your not checking your pointers before accessing their values for dereference. This will automatically lead to undefined behavior if the pointer is invalid (NULL or indeterminate). With each implementation below, note we don't access data via dereference unless the pointer is first-known as valid:
Implementation: insert()
void insert(int id, int priority)
{
struct process **pp = &head;
struct process *element = malloc(sizeof(*element);
element->id = id;
element->priority = priority;
while (*pp && (*pp)->priority >= priority)
pp = &(*pp)->next;
element->next = *pp;
*pp = element;
}
Implementation: pop()
Your pop() function appears to be designed to return the popped value. While this isn't entirely uncommon it has the undesirable side-effect of having no mechanism for communicating to the caller that the queue is empty without a sentinel-value of some sort (such as (-1) in your case. This is the primary reason most queues have a top(), pop(), and isempty() functional interface. Regardless, assuming (-1) is acceptable as an error condition:
int pop()
{
struct process *tmp = head;
int res = -1;
if (head)
{
head = head->next;
res = tmp->id;
free(tmp);
}
return res;
}
Implementation: popId()
Once again, looking for a specific node can be accomplished with a pointer-to-pointer in a fairly succinct algorithm, with automatic updating done for you due to using the actual physical pointers rather than just their values:
void popId(int id)
{
struct process ** pp = &head, *tmp = NULL;
while (*pp && (*pp)->id != id)
pp = &(*pp)->next;
if (*pp)
{
tmp = *pp;
*pp = tmp->next;
free(tmp);
}
}
I strongly advise stepping through each of these with a debugger to see how they work, particularly the insert() method, which has quite a lot going on under the covers for what is seemingly a small amount of code.
Best of luck
Bellow is the relevant code:
typedef struct Node_t {
ListElement data;
struct Node_t* next;
} Node;
struct List_t {
Node* head;
Node* tail;
Node* current;
int size;
CopyListElement copyF;
FreeListElement freeF;
};
static ListResult initializeNode(List list, ListElement element, Node* newNode){
printf("\nEntered initializeNode\n");
if ((list == NULL) || (element == NULL)) return LIST_NULL_ARGUMENT;
newNode = malloc(sizeof(Node));
if (newNode == NULL) return LIST_OUT_OF_MEMORY;
printf("\nWithin initializeNode, before copyF\n");
ListElement newElement = list->copyF(element);
printf("\nWithin initializeNode, after copyF\n");
if (newElement == NULL) return LIST_OUT_OF_MEMORY;
newNode->data = newElement;
printf("\nLast line within initializeNode\n");
return LIST_SUCCESS;
}
List listCreate(CopyListElement copyElement, FreeListElement freeElement){
//Check if there is a NULL argument.
if ((copyElement == NULL) || (freeElement == NULL)) return NULL;
//Check wether there is enough memory.
List newList = malloc(sizeof(List));
if (newList == NULL) return NULL;
//Initialize an empty List.
newList->head = NULL;
newList->tail = NULL;
newList->size = 0;
newList->current = NULL;
newList->copyF = copyElement;
newList->freeF = freeElement;
return newList;
}
ListResult listInsertFirst(List list, ListElement element){
printf("\nEntered listInsertFirst\n");
Node* newNode;
ListResult result = initializeNode(list, element, newNode);
printf("\n Node was initialized\n");
if (result != LIST_SUCCESS) {
return result;
}
printf("\nEntering logistic works within listInsertFirst\n");
//Finish logistic work within the Node.
newNode->next = list->head;
list->head = newNode;
list->size++;
printf("\nElement was inserted successfully\n");
printf("\nCheck list->CopyF within listInsertFirst\n");
list->copyF(element);
printf("\nCheck list->CopyF within listInsertFirst: PASSED\n");
return LIST_SUCCESS;
}
Within main function I'm trying:
List list = listCreate(©Int, &freeInt);
ListResult result;
int el=2;
//ListElement e1;
//ListElement e2;
result = listInsertFirst(list,&el);
printf("\nresult = %d\n", result);
result = listInsertFirst(list,&el);
printf("\nresult = %d\n", result);
After compiling and running I get:
Entered listInsertFirst
Entered initializeNode
Within initializeNode, before copyF
Within initializeNode, after copyF
Last line within initializeNode
Node was initialized
Entering logistic works within listInsertFirst
Element was inserted successfully
Check list->CopyF within listInsertFirst Segmentation fault: 11
For some reason the pointer [to function] list->copyF gets corrupted [I think].
I'm assuming this is C code, not C++, based on the tags. Given that you have a mix of data definitions and actual code statements, which I wouldn't expect to work in C, I'm not 100% sure it is real C, in which case I may be wrong about the error below.
First of all, the interface to initializeNode() doesn't do what you probably intend. You probably want:
static ListResult initializeNode(List list, ListElement element, Node** newNodep)
{
Node *newNode = malloc(sizeof(Node));
if (newNode == NULL) return LIST_OUT_OF_MEMORY;
ListElement newElement = list->copyF(element);
if (newElement == NULL) return LIST_OUT_OF_MEMORY;
newNode->data = newElement;
*newNodep = newNode;
return LIST_SUCCESS;
}
That way the Node you create gets passed back.
I don't know what CopyInt() does, but if it's really the function hitting the Bus Error the bug with initializeNode() can't be your problem. However, it's possible that you aren't seeing the output of all your printfs before the crash gets reported.
If CopyInt() does what I'd expect, it does something like:
ListElement CopyInt(int *val)
{
ListElement *e = malloc(sizeof(ListElement));
if (e)
e->val = *val;
return e;
}
The only way you are going to get a second-time bus error here is if you've messed up the data structures maintained by the library function malloc(). Unfortunately for that theory, I don't see anything worse than a memory leak here.
My guess that the bug that actually causes the crash is this line:
newNode->next = list->head;
Like #Arlie Stephens said - code for initializeNode doesn't do anything as the pointer is passed by value and the actual pointer still points to junk. So when you do newNode->next = list->head; you're basically writing to an unknown address and it's very likely to get a segmentation fault.
Why does it only happens on the second call? No idea, it's undefined behavior.
Crazy idea - it's possible that newNode->next is initialized to the address of copyF and trying to write into it cause you to corrupt copyF...Try printing the address of newNode->next and the address of copyF.