I'm reading an algorithms book and I found myself stuck on this bit. I create a doubly linked list and when I try to print out its contents it prints out what I believe is address or some other value that is not relevant to what I want. Here is the code:
typedef struct double_element *dElement;
struct double_element
{
int value;
dElement prev;
dElement next;
};
dElement createNewDListWithElements(int count)
{
dElement element = malloc(sizeof(dElement));
element->value = 1;
element->next = NULL;
element->prev = NULL;
dElement previous = element;
for (int i = 1; i < count; i++) {
dElement el = malloc(sizeof(dElement));
el->value = i;
el->next = NULL;
el->prev = previous;
previous->next = el;
previous = el;
}
return element;
}
void printDList(dElement node)
{
printf("printing doubly linked list:\n");
while (node) {
printf("%i\n", node->value);
node = node->next;
}
printf("end printing double linked list\n");
}
Here is the output:
printing doubly linked list:
1
1070320
1070336
1070352
1070368
1070384
1070400
1070416
1070432
1070448
end printing double linked list
Your problem is that you are trying to allocate space for a struct double_element, but you only ask for enough space to store a struct double_element*.
The problem is that you are allocating space for a pointer instead of the struct itself, the reason the dangerous typedef of the pointer, if you want to guarantee the allocation is correct regardless of the typedef's in your code you can do this
dElement element = malloc(sizeof(*element));
that would allocate space for the struct, just as if you had called
dElement element = malloc(sizeof(struct double_element));
you can see that the typedef is harmful, a pointer should be explicitly a pointer, so the correct way to write the code without falling in this kind of issue is
struct double_element *element = malloc(sizeof(struct double_element));
/* ^ don't skip this no matter what */
also, you should make clear what the struct names are and how you name your variables, you could for example use CamelCase for the struct names, and lower case with underscores for your variables, something like this
struct DoubleElement *element = ...
it would make it clear that DoubleElement is the name of a struct, and even though you can leave the struct instead of tyepdefing it, because that makes it even clearer.
Related
This is a code from my programming with C course that prints a list, using ADT structs.
typedef struct list{
int data;
struct list *next;
}list;
int is_empty(const list *l){
return(l==NULL);
}
void print_list(list *h, char *title){
printf("%s\n", title);
while(h!=NULL){
printf("%d :", h -> data);
h = h -> next;
}
}
int main()
{
list list_of_int;
list* head = NULL;
head = malloc(sizeof(list));
printf("size of the list = %lu\n",sizeof(list)); //this has to be an unsigned long
head -> data = 5;
head -> next = NULL;
print_list(head,"single element list");
printf("\n\n");
return 0;
}
My question is, how we used malloc() and the memory it created to create the list pointer head?
The purpose of malloc is "making" legal space and providing a pointer to it.
The following lines in your code make sure that legal space contains values which make a node.
This might seem short, but that's it.
(And I think you confirmed that you now understand. Otherwise I would consider it too short to be polite myself.)
I'm new to C.I am trying to create a doubly linked list where the data field is a structure. But when I output the elements, only the first field of the structure is correctly displayed.
struct n
{
int a;
int b;
};
typedef struct _Node {
struct n *value;
struct _Node *next;
struct _Node *prev;
} Node;
typedef struct _DblLinkedList {
size_t size;
Node *head;
Node *tail;
} DblLinkedList;
DblLinkedList* createDblLinkedList() {
DblLinkedList *tmp = (DblLinkedList*) malloc(sizeof(DblLinkedList));
tmp->size = 0;
tmp->head = tmp->tail = NULL;
return tmp;
}
void pushBack(DblLinkedList *list, struct n *value) {
Node *tmp = (Node*) malloc(sizeof(Node));
if (tmp == NULL) {
exit(3);
}
tmp->value = value;
tmp->next = NULL;
tmp->prev = list->tail;
if (list->tail) {
list->tail->next = tmp;
}
list->tail = tmp;
if (list->head == NULL) {
list->head = tmp;
}
list->size++;
}
void printInt(struct n *value) {
printf("%d, %d", value->a, value->b);
}
void printDblLinkedList(DblLinkedList *list, void (*fun)(struct n*)) {
Node *tmp = list->head;
while (tmp) {
fun(tmp->value);
tmp = tmp->next;
printf("\n");
}
}
So, I have a few questions. Did I declare the node value field correctly? Am I inserting the node at the end of the list correctly? Am I doing the output of doubly linked list items correctly? And where is my mistake and how to fix it?
Did I declare the node value field correctly?
That depends on what your intention was. In terms of storing a pointer to a struct n: yes.
Am I inserting the node at the end of the list correctly?
Yes.
Am I doing the output of doubly linked list items correctly?
Yes.
And where is my mistake and how to fix it?
The code works from my point-of-view but what can be misleading is how pushBack operates. pushBack takes the struct n pointer as-is and stores it in Node. You did not post the pushBack caller code but the current implementation can caused problems if the caller assumes that the struct n gets copied.
To illustrate that, consider the following:
struct n value;
value.a = 1;
value.b = 2;
pushBack(list, &value);
value.a = 3;
value.b = 4;
pushBack(list, &value);
By reusing the value, two linked list nodes will effectively contain the same values. Also, the inserted struct n pointer must remain valid throughout the lifetime of the list. So, inserting stack-allocated values (that will be deallocated later by leaving their scope) or freeing dynamically-allocated values too early might lead to incorrect values. As long as the caller knows that, this is not necessarily a problem.
There are usually 3 ways to handle memory ownership:
Data structure owns values (just like it owns nodes) and is responsible for freeing them
Data structure copies values and is responsible for freeing them
Caller owns values and is responsible for freeing them
For a linked list, there's lots of merit in the strategy #3, because a linked list can be created from existing values without any copying or ownership transfer which would most certainly require changes to existing code. That's basically what your code is doing at the moment.
I'm still learning how to program in C and I've stumbled across a problem.
Using a char array, I need to create a linked list, but I don't know how to do it. I've searched online, but it seems very confusing. The char array is something like this char arr[3][2]={"1A","2B","3C"};
Have a look at this code below. It uses a Node struct and you can see how we iterate through the list, creating nodes, allocating memory, and adding them to the linked list. It is based of this GeeksForGeeks article, with a few modifications. I reccommend you compare the two to help understand what is going on.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char value[2];
struct Node * next;
};
int main() {
char arr[3][2] = {"1A","2B","3C"};
struct Node * linked_list = NULL;
// Iterate over array
// We calculate the size of the array by using sizeof the whole array and dividing it by the sizeof the first element of the array
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
// We create a new node
struct Node * new_node = (struct Node *)malloc(sizeof(struct Node));
// Assign the value, you can't assign arrays so we do each char individually or use strcpy
new_node->value[0] = arr[i][0];
new_node->value[1] = arr[i][1];
// Set next node to NULL
new_node->next = NULL;
if (linked_list == NULL) {
// If the linked_list is empty, this is the first node, add it to the front
linked_list = new_node;
continue;
}
// Find the last node (where next is NULL) and set the next value to the newly created node
struct Node * last = linked_list;
while (last->next != NULL) {
last = last->next;
}
last->next = new_node;
}
// Iterate through our linked list printing each value
struct Node * pointer = linked_list;
while (pointer != NULL) {
printf("%s\n", pointer->value);
pointer = pointer->next;
}
return 0;
}
There are a few things the above code is missing, like checking if each malloc is successful, and freeing the allocated memory afterwards. This is only meant to give you something to build off of!
I'm trying to type a function that takes 2 linked list. One has the values to be printed and the second has positions for the linked list values to be printed. It gives me an error that i put as comment in the code.
Structs
typedef int Item;
typedef struct node_struct * link;
typedef struct list_struct * list;
struct node_struct {
Item item;
link next;
};
struct list_struct {
link first;
int length;
};
Function:
list sublist(list A, list pos_list) {
link tempOne;
link tempTwo;
link node = malloc(sizeof *node);
tempOne = pos_list->first;
tempTwo = A->first;
int counter;
while(tempOne->next != NULL)
{
counter = 0;
while(counter < tempOne->item && tempOne->next != NULL)
{
tempTwo = tempTwo->next;
counter = counter+1;
}
node->item = tempTwo->item; //EXC_BAD_ACCESS code:1
node = node->next;
tempTwo = A->first;
tempOne = tempOne->next;
counter = 0;
}
return node;
There are bunch of bad practices in the code which makes understanding (and hence debugging and maintaining) such code very difficult for you and for us.
You are creating a pointer typdef when there is no intention to hide the actual data behind the pointer
You are creating a linked list of positions and a linked list of data, using the same data type. I understand in your case both are int, but then don't use the misleading typedef int Item and simply stick to using int
tempOne and tempTwo are probably the worst naming options in this case, not only for calling the variables with non-intuitive names like temp, but also calling the first arg as Two and second arg as One - as counter-intuitive as it can get
I can see cases where you use 2 different structures node_struct (which frankly I would call node) and list_struct see node_structcomment), but in this example, you don't need list_struct, it only adds more confusion to the code.
You should really do the "find" job (the inner for loop)in a separate function, so you can easily handle errors, and not confuse the inner loop with the outer loop
With that out of the way, You haven't specified if the pos_list actually contains relative positions (position from previous position) or absolute positions (like array index). I will assume it is absolute position.
after you do node = node->next; you need to malloc it again. Or rather just malloc it before using it on line node->item = tempTwo->item; and get rid of the malloc out side the loops
I don't have a c compiler handy, so couldn't test it. But I don't see any other issues
EDIT
I noticed that the return value for sublist is always just the last node, instead of the first node in the linked list - this is obviously going to be a problem too.
Below is how I would write this code. Remember, this is not a debugged and tested code, but mere expression of the idea (first draft if you will)
typedef struct Node_ Node;
struct Node_ {
int Item;
Node* Next;
};
Node* GetNodeAt(Node *dataList, int indx) {
for (int i = 0; i < indx && dataList != NULL; ++i)
dataList = dataList->Next;
return dataList;
}
Node* SubList(Node *dataList, Node *posList) {
Node* origDataList = dataList;
Node *currentRetNode = malloc(sizeof(Node));
Node *prevRetNode = NULL, *returnList = currentRetNode;
while (posList->Next != NULL) {
// Find the node in dataList
Node *node = GetNodeAt(dataList, posList->Item);
// create/manage the linked list to be returned
prevRetNode = currentRetNode;
currentRetNode->Next = malloc(sizeof(Node));
currentRetNode->Item = node->Item;
currentRetNode = currentRetNode->Next;
posList = posList->Next; // move to the next index
}
free(currentRetNode);
if (prevRetNode == NULL)
returnList = NULL;
else
prevRetNode->Next = NULL;
return returnList;
}
I am studying the following C code:
typedef struct msg *m_;
struct msg
{
long from;
long to;
m_ link;
};
m_ queue;
I would like to see an example that explains the role of the pointer, i.e. m_, of the structure inside the structure itself m_ link!
Thank you very much.
To be pedantic: link is a pointer. m_ is not a pointer, it's a typedef. It is used to avoid the need to say "struct msg* link;" inside the struct definition.
As answered in the comment above, the queue is represented by a pointer to the first item, which has a pointer to the second (if any), and so on until you reach a NULL pointer.
It's important to take care when building such lists that no node points to itself or to any precursor, or you get an infinite loop chasing to the tail.
Pointers to the structure type inside the structure itself are very often used for linked lists, trees, etc. In your example, it is referring to a queue implementation.
Here is a very minimal example of a stack implementation using a linked list. The functions require the address of a stack pointer, and an empty stack is a NULL pointer.
struct linked_stack
{
int data;
struct linked_stack *next;
};
void linked_stack_push(linked_stack **stck, int data)
{
struct linked_stack *node = malloc(sizeof(struct linked_stack));
if (node != NULL)
{
node->data = data;
node->next = *stck;
}
*stck = node;
}
int linked_stack_top(linked_stack **stck)
{
if (*stck != NULL)
return (*stck)->data;
return 0; /* stack is empty */
}
void linked_stack_pop(linked_stack **stck)
{
struct linked_stack *node = *stck;
if (*stck != NULL)
{
*stck = node->next;
free(node);
}
}
Example usage:
int main(void)
{
struct linked_stack *stack = NULL;
linked_stack_push(&stack, 10);
printf("top of stack = %d\n", linked_stack_top(&stack));
linked_stack_pop(&stack);
return 0;
}