I'm working on a linked list implementation in C to get the hang of pointers and structs. Here is the basic code for my LL data structure:
struct Node {
void *data;
struct Node *next;
};
struct List {
struct Node *head;
};
void initList(struct List *list) {
list->head = 0;
}
struct Node *addFront(struct List *list, void *data) {
struct Node *newNode;
newNode->data = data;
newNode->next = list->head;
list->head = newNode;
return newNode;
}
Here is the test I run on it in the int main() function:
int main() {
/* test addFront */
double *data1;
double *data2;
*data1 = 10.5;
*data2 = 10.7;
struct List *newList;
initList(newList);
addFront(newList, data1);
printf("%s\n", newList->head->data);
addFront(newList, data2);
printf("%s\n", newList->head->data);
return 0;
}
My problem is that printf is not printing the output. As it stands now, it obviously doesn't print because %s doesn't match the data type, which is double. If I change the string format to %d, it gives me a segmentation fault. If I add a (double) cast, it says that the second argument has type double *, which confuses me because I thought the -> notation dereferenced a pointer.
I'm lost.
You are dereferencing data1 and data2 without assigning memory to them. Try:
double data1 = 10.5;
addFront(newList, &data1);
Alternatively you could do a malloc, although I don't think you should in this case.
Also, when you want to print them, try:
printf("%f\n", *(double *)newList->head->data);
You are not allocating memory for your double pointers data1 and data2.
Looks like, actually, you're not allocating memory for nearly any of your pointers.
All a pointer does by itself is reference an address in memory. It does not allocate the memory necessary to support the referenced structure or variable.
If you have
double *data1; // or any other kind of pointer
you need something like
data1 = (double *) malloc(sizeof(double));
THEN you can dereference all you like, eg
*data1 = 12.34;
But without that, your referencing a pointer to the Black Hole of Calcutta.
In addition to the 2 printf("%f") there are 4 malloc's missing:
I marked the changed lines with ###:
#include "stdlib.h"
#include "stdio.h"
struct Node {
void *data;
struct Node *next;
};
struct List {
struct Node *head;
};
void initList(struct List *list) {
list->head = 0;
}
struct Node *addFront(struct List *list, void *data) {
struct Node *newNode = malloc(sizeof(struct Node)); //###
newNode->data = data;
newNode->next = list->head;
list->head = newNode;
return newNode;
}
int main() {
/* test addFront */
double *data1 = malloc(sizeof(double)); //###
double *data2 = malloc(sizeof(double)); //###
*data1 = 10.5;
*data2 = 10.7;
struct List *newList = malloc(sizeof(struct List)); //###
initList(newList);
addFront(newList, data1);
printf("%f\n", *(double*)newList->head->data);//###
addFront(newList, data2);
printf("%f\n", *(double*)newList->head->data);//###
// TODO: free()'s //###
return 0;
}
What have you done to try to deal with the problem?
try using "assert.h" to ensure your assertions are right, or if statements with puts/exit.
In particular, if it doesn't print something, clearly what your are printing is not what you want to print, so somewhere along the lines, an assertion must fail, and your mind will "click" where you missed a step.
The reason I can't do this immediatly is because I am not you and I do not know what assertions you are making, so it will take me longer to place them than you would.
Also, as pointed above, you are not allocating memory for newNode, and accessing arbitrary memory, which is causing segmentation fault.
There I fixed it.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
struct Node {
void *data;
struct Node *next;
};
struct List {
struct Node *head;
};
void initList(struct List **newList)
{
struct List* tmpList = 0;
assert(newList != 0);
tmpList = (struct List*)malloc(sizeof(struct List*));
assert(tmpList != 0);
tmpList->head = 0;
*newList = tmpList;
}
void addFront(struct List* list, void* data)
{
struct Node* currNode = 0;
struct Node* prevNode = 0;
assert(list != 0);
assert(data != 0);
currNode = list->head;
while (currNode != 0) {
prevNode = currNode;
currNode = currNode->next;
}
if (prevNode == 0) {
list->head = (struct Node*)malloc(sizeof(struct Node));
list->head->data = data;
list->head->next = 0;
} else {
prevNode->next = (struct Node*)malloc(sizeof(struct Node));
prevNode->next->data = data;
prevNode->next->next = 0;
}
}
void test(const struct List *list)
{
const struct Node *iter;
assert(list != 0);
assert(list->head != 0);
iter = list->head;
while (iter != 0) {
assert(iter->data != 0);
printf("%f\n", *((double*)iter->data));
iter = iter->next;
}
}
int main()
{
double* data1 = (double*)malloc(sizeof(double));
double* data2 = (double*)malloc(sizeof(double));
*data1 = 10.5;
*data2 = 10.7;
struct List* newList = 0;
initList(&newList);
assert(newList->head == 0);
puts("pass[0].");
addFront(newList, data1);
assert(newList->head != 0);
assert(newList->head->data == data1);
puts("pass[1].");
addFront(newList, data2);
assert(newList->head != 0);
assert(newList->head->data == data1);
assert(newList->head->next != 0);
assert(newList->head->next->data == data2);
puts("pass[2].");
test(newList);
return 0;
}
Related
This question already has answers here:
Linked lists - single or double pointer to the head
(3 answers)
What is the reason for using a double pointer when adding a node in a linked list?
(15 answers)
Closed 10 months ago.
#include<stdio.h>
#include<stdlib.h>
void insert_front(struct node* head, int block_number);
void insert_rear(struct node* head, int block_number);
void print_list(struct node* head);
struct node {
int block_number;
struct node* next;
};
int main(void)
{
struct node* list = NULL;
insert_front(list, 10);
insert_rear(list, 20);
insert_front(list, 30);
insert_rear(list, 40);
print_list(list);
return 0;
}
void insert_front(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
void insert_rear(struct node* head, int block_number)
{
struct node* p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL) {
head = p;
}
else {
struct node* q = head;
while (q->next != NULL) {
q = q->next;
}
q->next = p;
}
}
void print_list(struct node* head)
{
struct node* p = head;
while (p != NULL) {
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
When I ran it, there was no result at all.
Now, in the insert_front function p->block_number = block_number, a message appears saying that the NULL pointer 'p' is being dereferenced... (The same thing appears in the insert_rear function.)
Could it be that I am declaring the pointer wrong?
Both insert_front and insert_rear need to convey possibly head modification back to the caller, and the caller needs to reap that information. Both should be declared to return struct node *, do so, and the code in main react accordingly. E.g.:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
struct node * insert_front(struct node *head, int block_number);
struct node * insert_rear(struct node *head, int block_number);
void print_list(struct node *head);
struct node
{
int block_number;
struct node *next;
};
int main(void)
{
struct node *list = NULL;
list = insert_front(list, 10);
list = insert_rear(list, 20);
list = insert_front(list, 30);
list = insert_rear(list, 40);
print_list(list);
return 0;
}
struct node *insert_front(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = head;
head = p;
return head;
}
struct node *insert_rear(struct node *head, int block_number)
{
struct node *p = malloc(sizeof(struct node));
p->block_number = block_number;
p->next = NULL;
if (head == NULL)
{
head = p;
}
else
{
struct node *q = head;
while (q->next != NULL)
{
q = q->next;
}
q->next = p;
}
return head;
}
void print_list(struct node *head)
{
struct node *p = head;
while (p != NULL)
{
printf("--> %d ", p->block_number);
p = p->next;
}
printf("\n");
}
Output
--> 30 --> 10 --> 20 --> 40
I leave the memory leaks for you to resolve.
In C all variables are passed by value – if you pass a pointer, then it is copied, too (not the pointed to object, of course...), and function parameters, apart from being initialised from outside, are nothing more than local variables. Thus via head = p; you just assign the local copy of the outside pointer, not the latter itself!
To fix that you have two options:
Return the new head and make the user responsible for re-assigning the returned value to his own head pointer.
Accept the head as pointer to pointer.
With second approach a user cannot forget to re-assign the (potentially) new head, so that's what I'd go with:
void insert_whichEver(node** head, int block_number)
{
// use `*head` where you had `head` before...
}
void demo()
{
node* head = NULL;
insert_front(&head, 1012);
}
And in insert_front drop return head;, a function with void cannot return anything concrete and does not require a return at all (but bare return; can be used to exit a function prematurely).
I am trying to implement a linked list using the given structure for a bigger project. The structure is defined below:
typedef struct node {
unint32_t size; // = size of the node
struct node * link; // = .next pointer
} * ListNode;
I was able to implement a linked list using struct node *. But when I attempt to use ListNode like in the following program:
typedef struct node {
unint32_t size;
struct node * link;
} * ListNode;
void insert_node (ListNode * head, unint32_t size) {
ListNode new_node = (ListNode) malloc (sizeof(ListNode));
new_node->size = size;
new_node->link = NULL;
if (head == NULL) {
head = &new_node;
}
else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main (int argc, char const * argv[]) {
ListNode head = NULL;
insert_node (&head, 10);
insert_node(&head, 20);
ListNode ptr = head;
while (ptr != NULL) {
printf ("%d ", ptr->size);
}
printf ("\n");
return 0;
}
I get a segmentation fault. Why is that? It even says that struct node * and ListNode are incompatible pointers/types. I thought they were the same struct just named differently.
A little clarification
typedef struct node {
unint32_t size;
struct node * link;
} *ListNode;
creates a type called ListNode. It is a pointer to a struct node. It is not a struct node
So when you do
sizeof(ListNode)
you get the size of a pointer, not the size of struct node
You needed to do
sizeof(struct node)
A very common thing to do is this
typedef struct node {
uint32_ size;
struct node* link;
} *PListNode, ListNode;
this creates 2 types
PlistNode which is a pointer to a struct node
ListNode which is a struct node
the 'P' is a reminder that this is a pointer
so now you can do
PListNode pn = malloc(sizeof(ListNode));
Since you supply a struct node** (a ListNode*) to insert_node, you need to dereference it to assign to it.
You malloc the size of a struct node* (a ListNode) but you need to malloc the size of a struct node.
You also need to do ptr = ptr->link in the loop in main.
Example:
void insert_node(ListNode* head, uint32_t size) {
// corrected malloc, you don't want the sizeof a pointer but the
// size of a `node`:
ListNode new_node = malloc(sizeof *new_node);
new_node->size = size;
new_node->link = NULL;
if (*head == NULL) { // corrected check (dereference head)
*head = new_node; // corrected assignment
} else {
ListNode current = *head;
while (current->link != NULL) {
current = current->link;
}
current->link = new_node;
}
}
int main() {
ListNode head = NULL;
insert_node(&head, 10);
insert_node(&head, 20);
// the below loop had no exit condition before:
for(ListNode ptr = head; ptr; ptr = ptr->link) {
printf("%d ", ptr->size);
}
printf("\n");
}
Demo
I have created a new struct that represents a linked list and two functions listDestroy and arr2list. The second function gets a generic array and converts it into a list. The code:
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(List* list, void freeElement(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
if (length == 0 || !copyElement || !freeElement) {
return NULL;
}
struct List* head = (struct List*) malloc(sizeof(struct List));
if (head == NULL) {
return NULL;
}
List* current_node = head;
for(int i = 0; i < length; i++) {
current_node->value = copyElement(array[i]);
struct List* new_node = (struct List*) malloc(sizeof(struct List));
if (new_node == NULL) {
listDestroy(head, freeElement);
return NULL;
}
current_node->next = new_node;
current_node = new_node;
}
return head;
}
I think that I have a problem with the copyElement(array[i]);. I want to pass a generic array of elements to arr2list but I'm not sure if void* array[] is the right way. If I change it to be void* array I get an error for array[i]. What is the right way to make it work? Is it possible to also show a working example?
The last node of the list ends up with a NULL next and a garbled value. I don't think this is what you wanted. Try this loop:
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = malloc(sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = copyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
This uses a pointer to pointer so that we can update head or next depending on where we are in the loop without an extra if condition. Note that the allocaction of head is inside the loop now, so we always allocate exactly as many nodes as we need.
void* array[] is completely valid in this scenario, although I don't see the point of copyElement.
Perhaps just remove it and use array[i] instead?
I'd also like to point out a few mistakes that you may want to fix in your code:
Don't cast the result of malloc and use sizeof(*var) instead of sizeof(type). They're unneeded and may cause issues later on if you change the type of head. So, change this (and any later occurrences):
struct List* head = (struct List*) malloc(sizeof(struct List));
to this:
struct List* head = malloc(sizeof(*head));
Consider returning struct List * from arr2list. Change this:
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
to this:
struct List* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
Also, use either struct List * or List *. Inconsistencies may make it hard to understand your code.
It may be clearer if you pass function pointers to your functions instead of just functions. So, instead of doing this:
returntype func(params),
do this:
returntype (*func)(params),
You may also want to change malloc calls to calloc calls. calloc zeroes out memory, which can help in debugging. Change:
malloc(...)
to:
calloc(1, ...)
Here's an example combining code fixes from Joshua's post and mine:
list.c:
#include <stdlib.h>
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(struct List* list, void (*freeElement)(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
struct List* arr2list(void* array[], int length, void (*freeElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
if (length == 0 || !freeElement) {
return NULL;
}
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = array[i];
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
test.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.c"
void free_element(void *el)
{
free(el);
}
int main(void)
{
List *list;
int ctr;
void *array[4];
for(ctr = 0; ctr < 4; ctr++)
{
/* Don't usually pass sizeof(type) to malloc(),
* but these are extenuating circumstances. */
array[ctr] = malloc(sizeof(int));
if(!array[ctr]) return 1;
*(int *)array[ctr] = ctr * 4;
}
list = arr2list(array, sizeof(array)/sizeof(array[0]), free_element);
while(list)
{
printf("%d\n", *(int *)list->value);
list = list->next;
}
listDestroy(list, free_element);
return 0;
}
Output:
0
4
8
12
One last note: you may consider creating a header file that defines these structures and functions (and remove the structure from list.c). Here's an example:
#ifndef LIST_H
#define LIST_H 1
typedef struct List { // Remove this from list.c
struct List* next;
void *value;
} List;
void listDestroy(struct List*, void (*)(void*));
struct List* arr2list(void* [], int, void (*)(void*));
#endif
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;
}
Hey i am starting to work on Huffman coding and I have a bit of a problem I getting this error
Segmentation fault (core dumped)
I understand it is caused by trying to reach memory you are not allow to but I can not realize what is the problem in my code, thank in advnace for the help!
src.txt - http://pastebin.com/kDf8nEhV
#include <stdio.h>
#include <stdlib.h>
int freq[256] = {0};
struct Node {
unsigned char m_ch;
int m_freq;
struct Node* m_ls, *m_rs;
struct Node* m_hls, *m_hrs;
};
struct Node* createNode(int freq, char ch);
void insertTree(struct Node** root, struct Node* n);
struct Node* getBinTree(FILE* fsrc);
void inorder(struct Node* root);
int main() {
FILE* fsrc;
struct Node* tree = (struct Node*)malloc(sizeof(struct Node));
fsrc = fopen("src.txt", "rb");
tree = getBinTree(fsrc);
inorder(tree);
return 1;
}
struct Node* createNode(int freq, char ch) {
struct Node* pNode = (struct Node*)malloc(sizeof(struct Node));
pNode->m_freq = freq;
pNode->m_ch = ch;
return pNode;
}
void insertTree(struct Node** root, struct Node* n) {
if (!(*root)) {
*root = n;
return;
}
if (n->m_freq < (*root)->m_freq) {
insertTree(&(*root)->m_ls, n);
} else {
insertTree(&(*root)->m_rs, n);
}
}
struct Node* getBinTree(FILE* fsrc) {
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
struct Node** root = (struct Node**)malloc(sizeof(struct Node*));
*root = (struct Node*)malloc(sizeof(struct Node));
int c, i;
while ((c = fgetc(fsrc)) != EOF) {
freq[c]++;
}
freq[255] = 1;
fclose(fsrc);
for (i = 0; i < 256; i++) {
if (freq[i] > 0) {
temp = createNode(freq[i], i);
insertTree(root, temp);
}
}
}
void inorder(struct Node* root) {
if (root != NULL) {
inorder(root->m_ls);
printf(" %d\n", root->m_freq);
inorder(root->m_rs);
}
return;
}
Your,
struct Node* getBinTree(FILE *fsrc)
is not returning anything.
You should enable compiler warnings, the compiler would have told you about that, the function is not returning a value, but you still assign it to tree in main().
But apart from that there is a serious problem with your code, a simple example
int main()
{
FILE *fsrc;
struct Node *tree = (struct Node*)malloc (sizeof(struct Node));
fsrc = fopen("src.txt","rb");
tree=getBinTree(fsrc);
inorder(tree);
return 1;
}
This single function has many problems,
You allocate new memory and point to it with tree, but you never use it because you overwrite the pointer here
tree = getBinTree(fsrc);
that causes a memory leak.
You don't check if the file was succesfuly opened, you must check
fsrc = fopen("src.txt", "rb");
if (fsrc == NULL)
return -1;
You don't need to cast malloc()
struct Node *tree = malloc(sizeof(*tree));
this is more robust, and easier to read.
You have to make sure that malloc() did not fail to allocate memory, when it does NULL is returned, so you need this when you do a malloc() that is actually required, for example in getBinTree()
struct Node *tree = malloc(sizeof(*tree));
if (tree == NULL)
return NULL;
i.e., copy malloc()'s behavior by returning NULL on failure.