Pointer arithmetic - c

I created a linked list with ten nodes. I want to get the address of the first node I created in the linked list. I am getting incorrect address value for the first node. This is the code which I wrote :
#include "singlyLinkedList.h"
#include <stddef.h> //for NULL
#include <stdlib.h> //for malloc
#include <stdio.h> //for printf
node *pNode;
void CreateLinkedList()
{
int i;
pNode = (node*)malloc(sizeof(node)); //create space for first node []
for(i=0;i<10;i++)
{
pNode->element = i; //enter value [0]
printf("Value is %d addr is %p\n",pNode->element,pNode);
pNode->nextPtr = (node*)malloc(sizeof(node)); //[0]->[]->NULL
pNode = pNode->nextPtr;
}
pNode->nextPtr=NULL;
}
//Function to get first node address
void GetFirstNodeAddress()
{
pNode = pNode-10*(sizeof(node));
printf("\n *** Value is %p",pNode);
}
int main()
{
CreateLinkedList();
GetFirstNodeAddress();
}

You assume that the 10 malloc's you do will result in 10 consecutive addresses. You handle it as if it is an array, yet the elemenents of the linked list are independent.
The way these linked lists usually work is that you initialise them and keep the first pointer to be returned later. Then grow more elements on the tail. You can not walk backwards in a single linked list.
I gave a code example in an earlier post today

You don't use pointer arithmetic in linked list implementations, at least not trivial ones. And you're populating your list incorrectly. You need to retain the head pointer. This is one such way to do it:
// Note: do NOT invoke on a non-empty pNode list
void CreateLinkedList()
{
node **pp = &pNode;
int i;
for (i=0;i<10;++i)
{
*pp = malloc(sizeof(**pp));
(*pp)->element = i;
pp = &(*pp)->nextPtr;
}
*pp = NULL;
}
How It Works
Just like pNode is a pointer to a node, pp is a pointer to a node *. During the lifetime of the loop pp always holds the address of the next pointer about to be filled with a new node allocation. After the allocation and node setup, pp is filled with the address of the nextPtr pointer of the node just-created. This continues until the end of the fill. At that point the pointer addressed by pp is the tail nextPtr and should be null-terminated (which is what *pp = NULL does). Step through this code in a debugger to see better how it works.
Personally I would pass the address of the head pointer as a parameter, but this is one immediate way to get your code running.

Try printf("\n *** Value is %p",(void *) &pNode);. & is typically the easiest way to get pointer addresses
also from what I know: pNode = pNode-10*(sizeof(node)); is incorrect.
when you are doing pointers, they point to areas in memory that are not necessarily contiguous (following in order in memory). Meaning you could have one pointer pointing to memory blocks 5-10, which also has a pointer to memory blocks 83-88. If you want to get the first node, create a pNode rootNode and assign your first created pNode to that. Then you can traverse it in a while loop as well as printing out the address as listed above or whatever else you please.

Related

How is it possible that I can treat a pointer to a linked list as if it's the linked list itself in this piece of code?

Could anyone care to explain why this piece of code written below works?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct node
{
int number;
struct node *next;
}
node;
int main(void)
{
node *first = NULL;
node *second = NULL;
node *third = NULL;
first = malloc(sizeof(node));
second = malloc(sizeof(node));
third = malloc(sizeof(node));
first->number =1;
first->next = second;
second->number =2;
second->next = third;
third->number = 3;
third->next = NULL;
printf("%d\n%d\n%d\n", first->number, second->number, third->number);
return 0;
}
From my understanding, when I allocate memory to a node *, I am technically allowing that node pointer to point to an array of nodes. Therefore, node * would be a different data type compared to a single node, and number and next would be components that are exclusive to a single node. However, first->number and first->next can both be assigned values, which confuses me, because that means first, which was initialized as a node * can now be accessed as if it is a single node.
From my understanding, when I allocate memory to a node *
You allocate a memory area with enough space to store a node.
I am technically allowing that node pointer to point to an array of nodes. Therefore, node * would be a different data type compared to a single node, and number and next would be components that are exclusive to a single node.
first = malloc(sizeof(node));
first is a pointer to the memory area which has been given by malloc. There is nothing related to any array here. first will refer to a node, which will be different from second node and different from third node.
first->number =1;
first->next = second;
second->number =2;
second->next = third;
third->number = 3;
third->next = NULL;
printf("%d\n%d\n%d\n", first->number, second->number, third->number);
This code is pretty simple, he create 3 different nodes, set their values number and print them.
If you want a continuous memory area, you can write:
array = malloc(3*sizeof(node));
In this case, the memory area will be continious. You could use the syntax array[0] to refer the first node, array[1] to refer to the second node and array[2] to refer to the third node.
From my understanding, when I allocate memory to a node *, I am technically allowing that node pointer to point to an array of nodes. Therefore, node * would be a different data type compared to a single node, and number and next would be components that are exclusive to a single node.
Untrue. It may be easier to distinguish between a linked list and an array when we look at time complexity of various operations.
In an array, elements are adjacent to each other and occupy one contiguous block of memory. Therefore, if you want to access some element, all you need is simple arithmetic on pointers and you can immediately "jump" to the right location.
Linked lists, on the other hand, require you to step through each element, because it's not until you've stepped into one that you'll know where the next one lies in memory. To get to the nth element of a linked list, you need to iterate through n-1 prior elements.
Consider the following code, which can be used to find the last element in a linked list:
node *last;
for (last = first; last && last->next; last = last->next);
printf("Address of the last node: %p\n", last);
It actually doesn't matter which node you pass as the initial value of last, because all nodes are linked up in such a way that you will always arrive at the same result. The only difference is how many nodes you'll have to jump through before you get there.
Perhaps your confusion stems from the fact that struct node's next member's type is a pointer to another node, and sometimes we use pointers to describe an array. That is not the case here, the pointer only represents a single element.

Understanding code for creating a singly linked list using double pointer in C

I am trying to understand how the code below for creating a singly linked list works using a double pointer.
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
void push(struct Node** headRef, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
//Function to implement linked list from a given set of keys using local references
struct Node* constructList(int keys[], int n) {
struct Node *head = NULL;
struct Node **lastPtrRef = &head;
int i, j;
for(i = 0; i < n; i++) {
push(lastPtrRef, keys[i]);
lastPtrRef = &((*lastPtrRef)->next); //this line
if((*lastPtrRef) == NULL) {
printf("YES\n");
}
}
return head;
}
int main() {
int keys[] = {1, 2, 3, 4};
int n = sizeof(keys)/sizeof(keys[0]);
//points to the head node of the linked list
struct Node* head = NULL;
head = constructList(keys, n); //construct the linked list
struct Node *temp = head;
while(temp != NULL) { //print the linked list
printf(" %d -> ", temp->data);
temp = temp->next;
}
}
I understand the purpose of using the double pointer in the function push(), it allows you to change what the pointer headRef is pointing to inside the function. However in the function constructList(), I don't understand how the following line works:
lastPtrRef = &((*lastPtrRef)->next);
Initially lastPtrRef would be pointing to head which points to NULL. In the first call to push(), within the for loop in constructList(), the value that head points to is changed (it points to the new node containing the value 1). So after the first call to push(), lastPtrRef will be pointing to head which points to a node with the value of 1. However, afterwards the following line is executed:
lastPtrRef = &((*lastPtrRef)->next);
Whereby lastPtrRef is given the address of whatever is pointed to by the next member of the newly added node. In this case, head->next is NULL.
I am not really sure what the purpose of changing lastPtrRef after the call to push(). If you want to build a linked list, don't you want lastPtrRef to have the address of the pointer which points to the node containing 1, since you want to push the next node (which will containing 2) onto the head of the list (which is 1)?
In the second call to push() in the for loop in constructList, we're passing in lastPtrRef which points to head->next (NULL) and the value 2. In push() the new node is created, containing the value 2, and newNode->next points to head->next which is NULL. headRef in push gets changed so that it points to newNode (which contains 2).
Maybe I'm understanding the code wrong, but it seems that by changing what lastPtrRef points to, the node containing 1 is getting disregarded. I don't see how the linked list is created if we change the address lastPtrRef holds.
I would really appreciate any insights as to how this code works. Thank you.
This uses a technique called forward-chaining, and I believe you already understand that (using a pointer-to-pointer to forward-chain a linked list construction).
This implementation is made confusing by the simple fact that the push function seems like it would be designed to stuff items on the head of a list, but in this example, it's stuffing them on the tail. So how does it do it?
The part that is important to understand is this seemingly trivial little statement in push:
newNode->next = *headRef
That may not seem important, but I assure you it is. The function push, in this case, does grave injustice to what this function really does. In reality it is more of a generic insert. Some fact about that function
It accepts a pointer-to-pointer headRef as an argument, as well as some data to put in to the linked list being managed.
After allocating a new node and saving the data within, it sets the new node's next pointer to whatever value is currently stored in the dereferenced headRef pointer-to-pointer (so.. a pointer) That's what the line I mentioned above accomplishes.
It then stores the new node's address at the same place it just pulled the prior address from; i.e. *headRef
Interestingly, it has no return value (it is void) further making this somewhat confusing. Turns out it doesn't need one.
Upon returning to the caller, at first nothing may seem to have changed. lastPtrRef still points to some pointer (in fact the same pointer as before; it must, since it was passed by value to the function). But now that pointer points to the new node just allocated. Further, that new node's next pointer points to whatever was in *lastPtrRef before the function call (i.e. whatever value was in the pointer pointed to by lastPtrRef before the function call).
That's important. That is what that line of code enforces, That means if you invoke this with lastPtrRef addressing a pointer pointing to NULL (such as head on initial loop entry), that pointer will receive the new node, and the new node's next pointer will be NULL. If you then change the address in lastPtrRef to point to the next pointer of the last-inserted node (which points to NULL; we just covered that), and repeat the process, it will hang another node there, setting that node's next pointer to NULL, etc. With each iteration, lastPtrRef addresses the last-node's next pointer, which is always NULL.
That's how push is being used to construct a forward linked list. One final thought. What would you get for a linked list if you had this:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
void push(struct Node** headRef, int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *headRef;
*headRef = newNode;
}
int main()
{
//points to the head node of the linked list
struct Node* head = NULL;
push(&head, 1);
push(&head->next, 2);
push(&head->next, 3);
for (struct Node const *p = head; p; p = p->next)
printf("%p ==> %d\n", p, p->data);
}
This seemingly innocent example amplifies why I said push is more of a generic insert than anything else. This just populates the initial head node.
push(&head, 1);
Then this appends to that node by using the address of the new node's next pointer as the first argument, similar to what your constructList is doing, but without the lastPtrRef variable (we don't need it here):
push(&head->next, 2);
But then this:
push(&head->next, 3);
Hmmm. Same pointer address as the prior call, so what will it do? Hint: remember what that newNode->next = *headRef line does (I droned on about it forever; I hope something stuck).
The output of the program above is this (obviously the actual address values will be different, dependent to your instance and implementation):
0x100705950 ==> 1
0x10073da90 ==> 3
0x100740b90 ==> 2
Hope that helps.

simple linked list failing to print

I am learning how to make a linked list, but its failing to print out anything at all, and I cant figure out why??? please help. I believe it has something to do with my pointers but I don't know what it is.
#include <stdio.h>
#include <stdlib.h>
// typedef is used to give a data type a new name
typedef struct node * link ;// link is now type struct node pointer
/*
typedef allows us to say "link ptr"
instead of "struct node * ptr"
*/
struct node{
int item ;// this is the data
link next ;//same as struct node * next, next is a pointer
};
void printAll(link head); // print a linked list , starting at link head
void addFirst(link ptr, int val ); // add a node with given value to a list
link removeLast(link ptr); // removes and returns the last element in the link
//prints the link
void printAll(link head){
link ptr = head;
printf("\nPrinting Linked List:\n");
while(ptr != NULL){
printf(" %d ", (*ptr).item);
ptr = (*ptr).next;// same as ptr->next
}
printf("\n");
}
//adds to the head of the link
void addFirst(link ptr, int val ){
link tmp = malloc(sizeof(struct node));// allocates memory for the node
tmp->item = val;
tmp->next = ptr;
ptr = tmp;
}
// testing
int main(void) {
link head = NULL;// same as struct node * head, head is a pointer type
//populating list
for(int i = 0; i<3; i++){
addFirst(head, i);
}
printAll(head);
return 0;
}
output:
Printing Linked List:
Process returned 0 (0x0) execution time : 0.059 s
Press any key to continue
It's because you're passing a null pointer to your function and the condition for exiting the loop is for that pointer to be null, so nothing happens.
Your addFirst function takes a pointer's value, but it cannot modify the head that you declared inside of main().
To modify head you need to pass a pointer to link, then you can dereference that pointer to access your head and you can then change it.
void addFirst(link *ptr, int val ){
link tmp = malloc(sizeof(struct node));// allocates memory for the node
tmp->item = val;
tmp->next = *ptr;
*ptr = tmp;
}
Now you can change the head pointer. Just remember to pass the address to it when calling the function. addFirst(&head,i)
In the for loop
for(int i = 0; i<3; i++){
addFirst(head, i);
}
you create a bunch of pointers which all point to NULL. head is never changing since pointer itself is passed "by value". E.g. head is copied and all modifications to the pointer itself in addFirst are not visible outside.
This is the same as with say int. Imagine void foo(int x);. Whatever this function does to x is not visible outside.
However changes to the memory which link ptr points to are visible of course.
E.g. this line does nothing:
tmp->next = ptr;
ptr = tmp; <=== this line
}
You can fix this in several ways. One is to return new node from addFirst and another one is to make link ptr to be a pointer to pointer: link *ptr. Since in this case you want to change pointer value (not pointee value):
//link *ptr here a pointer to pointer
void addFirst(link * ptr, int val ){
link tmp = malloc(sizeof(struct node));// allocates memory for the node
tmp->item = val;
tmp->next = *ptr; //<<changed
*ptr = tmp; //<<changed
}
Do not forget to update declaration above also. And the call:
void addFirst(link * ptr, int val ); // add a node with given value to a list
...
for(int i = 0; i<3; i++){
addFirst(&head, i);
}
Then this code produces:
Printing Linked List:
2 1 0
Added:
It's important to understand that working with linked list requires working with two different types of data.
First is struct node and you pass around this type of data using links.
Second is head. This is a pointer to the very first node. When you would like to modify the head you find it is not a "node". It is something else. It's a "name" for the first node in the list. This name by itself is a pointer to node. See how memory layout for head is different from the list itself.
head[8 bytes]->node1[16 bytes]->node2[16 bytes]->...->nodek[16 bytes]->NULL;
by the way - the only thing which have lexical name here is head. All the nodes do not have name and accessible through node->next syntax.
You can also imagine another pointer here, link last which will point to nodek. Again this will have different memory layout from nodes itself. And if you would like to modify that in a function you will need to pass to function pointer to that (e.g.pointer to pointer).
Pointer and data it points to are different things. In your mind you need to separate them. Pointer is like int or float. It is passed "by value" to functions. Yes link ptr is already pointer and that permits you to update the data it points to. However the pointer itself is passed by value and updates to pointer (in your case ptr=tmp) are not visible outside.
(*ptr).next=xxx will be visible of course because data is updated (not pointer). That means you need to do one extra step - make changes to your pointer visible outside of function, e.g. convert the pointer itself (head) into data for another pointer, e.g. use struct node **ptr (first star here says this is pointer to a node, and the second star converts that pointer to data for another pointer.

How can a Linked List be implemented using only pointers (w/o structures)?

I'm trying to create a linked list without using structures in C.
I want to be able to store an int variable on every node and a pointer to the next node, add unlimited numbers to the list, remove the first item, print all of the elements, etc.
I was thinking that every node of type int** should have 2 pointers of type int*.
the first one will point to an int address and the second will point to NULL.
Then, if I like to add a number to the list, I'll use the last pointer to point to a new allocated node of type int** and so on.
I'm having trouble writing the proper code for this though, and can't seem to reach to the actual int values. See the image below:
You can achieve this by allocating two uintptr_t each time: the first allocated memory space will be responsible for storing the value of the integer and the second one will be pointing to the next memory location.
uintptr_t nodeFirst = malloc(2 * sizeof(uintptr_t));
...
...
uintptr_t nodeNext = malloc(2 * sizeof(uintptr_t));
....
....
*nodeFirst = someIntValue;
*(nodeFirst + 1) = nodeNext;
...
The fact is, my solution above is still using the struct analogy, but w/o the struct keyword.
Here is a complete solution of a LinkedList managed as int ** pointers.
Step 1 - the addNode() function to add one node to the int **head.
int **addNode(int **head, int ival)
{
int **node = malloc(2 * sizeof(int *));
// don't forget to alloc memory to store the int value
node[0] = malloc(sizeof(int));
*(node[0]) = ival;
// next is pointing to NULL
node[1] = NULL;
if (head == NULL) {
// first node to be added
head = node;
}
else {
int **temp;
temp = head;
// temp[1] is the next
while (temp[1]!=NULL) {
// cast needed to go to the next node
temp = (int **)temp[1];
}
// cast needed to store the next node
temp[1] = (int *)node;
}
return (head);
}
Step 2 - a function display() to explore the current linkedlist.
void display(int **head)
{
int **temp;
int i = 0;
temp = head;
printf("display:\n");
while (temp!=NULL) {
// temp[0] is pointing to the ivalue
printf("node[%d]=%d\n",i++,*(temp[0]));
temp = (int **)temp[1];
}
printf("\n");
}
Step 3 - the popNode() function to remove the first node.
int **popNode(int **head)
{
int **temp;
if (head!=NULL) {
temp = (int **)head[1];
// don't forget to free ivalue
free(head[0]);
// then free the next pointer
free(head[1]);
head = temp;
}
return (head);
}
Step 4 - then an example of main() function using the linkedlist.
int main()
{
int **head = NULL;
head = addNode(head,111);
head = addNode(head,222);
head = addNode(head,333);
display(head);
// display:
// node[0]=111
// node[1]=222
// node[2]=333
head = popNode(head);
display(head);
// display:
// node[0]=222
// node[1]=333
while ((head = popNode(head))!=NULL);
display(head);
// display:
return (0);
}
Allocate two arrays, both of which are stored as pointers. In C, they can be the pointers you get back from calloc(). The first holds your node data. We can call it nodes. The second is an array of pointers (or integral offsets). We can call it nexts. Whenever you update the list, update nodes so that each nexts[i] links to the next node after the one that contains nodes[i], or an invalid value such as NULL or -1 if it is the tail. For a double-linked list, you’d need befores or to use the XOR trick. You’ll need a head pointer and some kind of indicator of which elements in your pool are unallocated, which could be something simple like a first free index, or something more complicated like a bitfield.
You would still need to wrap all this in a structure to get more than one linked list in your program, but that does give you one linked list using no data structure other than pointers.
This challenge is crazy, but a structure of arrays isn’t, and you might see a graph or a list of vertices stored in a somewhat similar way. You can allocate or deallocate your node pool all at once instead of in small chunks, it could be more efficient to use 32-bit offsets instead of 64-bit next pointers, and contiguous storage gets you locality of reference.

C Linked list only contains first element...not sure what happens to rest

I posted a question a few days ago about a linked list in C. I thought everything was ok then the prof emails us saying that instead of this signature:
int insert_intlist( INTLIST* lst, int n); /* Inserts an int (n) into an intlist from the beginning*/
He accidentally meant:
int insert_intlist( INTLIST** lst, int n); /* Inserts an int (n) into an intlist from the beginning*/
I thought to myself cool now that I have a pointer to a pointer I can move the pointer outside of main and when I return to main I will still have my complete linked list.
He starts off with giving us this:
INTLIST* init_intlist( int n )
{
INTLIST *lst; //pointer to store node
lst = (INTLIST *)malloc(sizeof(INTLIST)); //create enough memory for the node
lst->datum = n; //set the value
lst->next = NULL; //set the pointer
return lst; //return the new list
}
Which is simply to initialize the list like so in main:
if (lst==NULL)
lst = init_intlist(i);
else
insert_intlist(lst, i);
lst is of type INTLIST* so its defined as INTLIST* lst. So I read in some numbers from a text file like 1 3 4 9.
It is supposed to create a linked list from this...so the first number would go to init_intlist(1); And that was defined above. Then it grabs the next number 3 in this case and calls insert_intlist(lst, 3). Well here is my insert_intlist and all I want to do is insert at the beginning of the list:
int insert_intlist(INTLIST** lst, int n )
{
INTLIST* lstTemp; //pointer to store temporary node to be added to linked list
lstTemp = (INTLIST *)malloc(sizeof(INTLIST)); //create enough memory for the node
lstTemp->datum = n; //assign the value
//check if there is anything in the list,
//there should be, but just in case
if(*lst == NULL)
{
*lst=lstTemp;
lstTemp->next=NULL;
}
else
{
lstTemp->next = *lst; //attach new node to the front
*lst = lstTemp; //incoming new node becomes the head of the list
}
return 0;
}
So if the list contained 1 initially this function would simply create a new node and then make this temp node->next point to the head of the list (which I thought was lst) and then reassign the head of the list to this new temp node.
It all looks like it is running right but when I try to print my list to the screen it only prints the number 1.
Anyone have any clues as to what I am doing wrong?
You're being passed a pointer to a pointer. You want to alter the pointer that is being pointed to, not the pointer to a pointer itself. Does that make sense?
if(lst == NULL)
Here you're checking to see if you were passed a NULL pointer. Good practice for error checking, but not for what you were doing right there. If lst is NULL, then you don't even have a pointer to a pointer, can't do anything, and should return a nonzero error code without doing anything else.
Once you're sure your pointer is not NULL, then you look at the pointer it's pointing to (*lst). The pointed-to pointer is the pointer to the first list item. If that pointer is NULL, then you change it to the new item's pointer. Basically, where you use lst you should be using *lst or (*lst). (REMEMBER: the * operator runs after the -> operator! So to get a field in the object pointed to by the pointer that is pointed to by lst [pant, pant], you use (*lst)->whatever.)
P.S. This kind of pointer work is critical to learn to be a good programmer, especially with C.
P.P.S. The other thing you got wrong is that instead of
insert_intlist(lst, i);
you're supposed to call it like
insert_intlist(&lst, i);
... and, for brownie points, check the return code for errors.
The first problem that pops into my mind is that in insert_intlist() you're doing lst = lstTemp;. This should be *lst = lstTemp;. This way you assign to the list pointer that you were supplied rather than to the list pointer pointer (which does not update anything outside of the function).
Since you are using a pointer to another pointer in the insert function, you can change at which memory location the latter actually points to. I changed the insert code a bit and it works fine:
int insert_intlist(INTLIST** lst, int n )
{
INTLIST* lstTemp; //pointer to store temporary node to be added to linked list
lstTemp = (INTLIST *)malloc(sizeof(INTLIST)); //create enough memory for the node
lstTemp->datum = n; //assign the value
//check if there is anything in the list,
//there should be, but just in case
if(*lst == NULL)
{
lstTemp->next=NULL;
*lst = lstTemp;
}
else
{
lstTemp->next = *lst; //attach new node to the front
*lst = lstTemp; //incoming new node becomes the head of the list
}
return 0;
}
EDIT: I see you edited your question. In that case, maybe you are calling the insert function in the wrong way in main(). Try this
int main()
{
INTLIST *head;
head = init_intlist(42);
insert_intlist(&head, 41);
display(head);
return 0;
}
Check to see if lstTemp->next == NULL after lstTemp->next=lst;

Resources