I was trying to understand better how the memory in the linked list is allocated so I made a simple program in order to see where the addresses are stored.
#include <stdio.h>
struct node {
int data;
struct node* next;
};
int main()
{
struct node first;
struct node second;
struct node third;
struct node *aux; //pointer to go through list
first.data = 1;
second.data = 2;
third.data = 3;
first.next = &second;
second.next = &third;
third.next = NULL;
aux = &first;
while (aux)
{
printf("%p\n", aux); //printing each address
aux = aux->next;
}
return 0;
}
And we get the output:
0x7fff14fabac0
0x7fff14fabad0
0x7fff14fabae0
So there is 1 byte difference between nodes.
So basically first = second - 1. How come there are spaces in memory left for integers since sizeof(int) equals 4 bytes, and we advance only by 1 byte?
You are ignoring the last digit, the difference is 16 bytes. The 16 bytes are most likely a result of 8 byte alignment of your system.
Related
void AlternatingSplit(struct Node* source, struct Node** aRef,
struct Node** bRef)
{
/* split the nodes of source to these 'a' and 'b' lists */
struct Node* a ;
struct Node* b;
struct Node* current = source;
if(current){
a=current;
b=current->next;
current=b->next;
a->next=NULL;
b->next=NULL;
}
while(current) {
a->next=current;
b->next=current->next;
if(b)
current=b->next;
b=b->next;
a=a->next;
}
*aRef = a;
*bRef = b;
}
I am getting segmentaton fault here i dont know why pls help.
This question is to alternating split linkedlist nodes. I m using two pointers a and b and adding to it alternatingly but its giving error . pls help me
Like most linked-list rearrangement exercises, pointers to pointers make the job much, much easier. The point of this exercise it to flex your ability to change the next pointers without ever changing the data values of said-same. Pointers to pointers are an excellent way to do that in C.
This is especially trivial because you were already provided the target pointer-to-pointer arguments that we can reuse for building each list. How that works is best understood by demonstrating a technique for building a forward-chained linked list using a single head pointer and a pointer to pointer p:
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
Yes, it needs error checking, but the algorithm is what to focus on here. This code uses only pp to build the actual list. The rule is this: pp is a pointer to pointer to Node, and always holds the address of the next pointer to Node to populate. That's what pointers to pointers do: hold addresses of pointers. In this case pp initially holds the address of the head pointer. With each new node added pp takes the address of the next pointer of the previously just-added node. Makes sense, right? That will be the next pointer where we want to hang the next node. This process continues until we finish the loop. At that pointer pp holds the address of the last node's next pointer, which we set to NULL to terminate the list.
Now, knowing what we learned above, consider this:
void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
while (source)
{
*a = source;
a = &(*a)->next;
source = source->next;
if (source)
{
*b = source;
b = &(*b)->next;
source = source->next;
}
}
*a = *b = NULL;
}
Example
A short example using both the forward-chaining build algorithm I showed first, and the split algorithm I showed after, appears below. Some utility functions for printing the list are included. I leave freeing the lists (there are two now, remember to walk both and free each node) as an exercise for you:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node *next;
};
void AlternatingSplit(struct Node* source, struct Node** a, struct Node** b)
{
while (source)
{
*a = source;
a = &(*a)->next;
if ((source = source->next))
{
*b = source;
b = &(*b)->next;
source = source->next;
}
}
*a = *b = NULL;
}
void PrintList(struct Node const *p)
{
while (p)
{
printf("%d ", p->data);
p = p->next;
}
fputc('\n', stdout);
}
int main(void)
{
struct Node *head, **pp = &head;
for (int i = 1; i <= 20; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->data = i;
pp = &(*pp)->next;
}
*pp = NULL;
PrintList(head);
struct Node *a = NULL, *b = NULL;
AlternatingSplit(head, &a, &b);
PrintList(a);
PrintList(b);
return EXIT_SUCCESS;
}
Output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 3 5 7 9 11 13 15 17 19
2 4 6 8 10 12 14 16 18 20
There are few errors in your code -
Trying to access node->next , without checking whether node exists or not .
Not tackling the corner cases depending on the length of linked list (i.e. if length (linked list) < 3 )
And then comes the blunder , you are trying to make the new linked lists and then in the end aRef and bRef is assigned to the last node in their respective linked lists.
Try to deal with these problems and for reference you can see the code below.
void AlternatingSplit(struct Node* source, struct Node** aRef,
struct Node** bRef)
{
struct Node* a,b;
struct Node* current = source;
if(current){
a=current;
b=current->next;
// moving 'current' one step at a time will secure the code from crashing for corner cases
current = current->next;
if(b)
current=b->next;
a->next=NULL;
b->next=NULL;
//link aRef bRef right here
*aRef = a;
*bRef = b;
}
else {
*aRef = source; // Null
*bRef = source; // Null
return;
}
while(current)
{
a->next=current;
a=a->next;
b->next=current->next;
b=b->next;
current=current->next;
if(b){
current = b->next;
}
}
b->next = NULL;
a->next = NULL;
}
Hope this will help .
Keep asking , keep growing :)
While writing an adjacency list from scratch I'm facing some problem with addressing and allocating memory for an array of struct. (ignore directed/undirected list).After hours of debugging I've found the code is keeping (updates) only the last two inputs in the adjacency list. I want to know what and how actually I'm messing up the memory allocation and accessing it.
Don't forget to give me further study links on this topic/issue, please. Thank's in advance.
Here's my code-
/*a single node of an adjacency list*/
typedef struct adjList{
int dest;
struct adjList *next;
} adjList;
/*Image of a graph...*/
typedef struct Image{
int source;
adjList *head;
} Image;
void add_adj_edge(Image graph[], int source, int destiny);
int main() {
int vertices = 6;
Image graph[vertices];
//need not to mention detailed here
// initialize_graph(graph, vertices);
add_adj_edge(graph, 1, 2);
add_adj_edge(graph, 1, 4);
add_adj_edge(graph, 1, 5);
add_adj_edge(graph, 1, 6);
print_graph(graph, vertices);
printf("graph[1].head->dest: %d\n", graph[1].head->dest);
return 0;
}
void add_adj_edge(Image *graph, int src, int dest){
adjList *cache = malloc(sizeof(adjList));
/*create a single node*/
cache->dest = dest;
cache->next = NULL;
if(graph[src].head == NULL){
graph[src].head = cache;
}
else{
while( graph[src].head->next != NULL){
graph[src].head = graph[src].head->next;
}
graph[src].head->next = cache;
}
return;
}
The output
node: 1 5 6
node: 2
node: 3
node: 4
node: 5
node: 6
graph[1].head->dest: 5
Instead of
node: 1 2 4 5 6
node: 2
node: 3
node: 4
node: 5
node: 6
graph[1].head->dest: 2
As I mentioned as comment, your source code has some missing and also misunderstanding on how to update a linked-list.
First problem: (allocating Image graph[vertices]; in your main() doesn't initialize value).
It is necessary to set adjList *head; property to NULL to be sure
that if(graph[src].head == NULL) will be true at the first access.
int vertices = 6;
Image graph[vertices];
for(int i=0;i<vertices;i++) {
graph[i].head = NULL; // list is empty
graph[i].source = 0; // or what ever you want
}
Second problem: (when adding a new node at the end of a linked-list, it is necessary to use a temporary variable to explore previous node).
If you are using graph[src].head = graph[src].head->next; you will
overwrite all previous nodes by the last one.
Use the following method in add_adj_edge()to explore nodes:
adjList *pTmp;
// point to the first node
pTmp = graph[src].head;
// explore node until the last has no node
while( pTmp->next != NULL){
pTmp = pTmp->next;
}
// update the next node
pTmp->next = cache;
#include <stdio.h>
#include <malloc.h>
typedef struct Node {
int value; //4
struct Node* next; //4
}Node;
Node *create();
void add();
void del();
void search();
Node *create(int v) {
Node *first;
first = (Node *)(calloc(1,sizeof(*first)));
first->value = v;
first->next = NULL;
return first;
}
void add(Node **head,int v) {
Node *p;
p = (Node *)(calloc(1,sizeof(*p)));
p->value = v;
p->next = *head;
*head = p;
}
void search(Node *head) {
Node *p;
p=head;
while(p != NULL) {
printf("address is %d;value address is %d;next address is %d;next content is %d\n",p,&(p->value),&(p->next),p->next);
p = p->next;
}
}
int main() {
Node *head;
head = create(0);
add(&head,1);
add(&head,2);
add(&head,3);
search(head);
}
sizeof(Node) == 8, but why is every node's size in the heap is 16 bytes? thinks
(my system is 32bit).
struct node is 4bytes + 4bytes = 8bytes.
The nodes sizes aren't 16 bytes, it's just that malloc() chooses to skip 8 bytes of memory for some reason, likely for its own bookkeeping. If you want to conserve memory, do few large allocations, not many small ones, or else the bookkeeping overhead can cost quite a lot.
well, even if the memory allocated between calls to calloc() was continuous for you program (which you cannot make sure), don't forget that the lib c has 'private' data stored in the hunk of memory you allocated.
usually there is a header like:
struct hdr
{
size_t size; /* Exact size requested by user. */
unsigned long int magic; /* Magic number to check header integrity. */
struct hdr *prev;
struct hdr *next;
__ptr_t block; /* Real block allocated, for memalign. */
unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
};
(code from)
You may see that the block actually the buffer of data that you'll get when calling malloc()/calloc(), is surrounded by a lot of extra data (ok, here is special case for debug, thus there are probably extra magics).
The errors involved in your code were logic errors related to the various list functions. When you have a create function, that functions job is to allocate memory for the node and assign any values required. It does not worry about which node it is dealing with.
Conversely, your add function does NOT allocate anything, it simply calls create to handle that work and then its job is merely properly wiring pointers and next->pointers to the proper node.
Since you are dealing with a head node that contains data, you have 3 possible conditions for add; (1) when head is NULL; (2) when head->next is NULL; and (3) all remaining additions.
Putting those pieces together and adding a print function, your code could look like the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value; //4
struct Node* next; //4
} Node;
/* function prototypes */
Node *create (int v);
void add (Node **head, int v);
void del ();
void search (Node *head);
void printvalues (Node *head);
int main (void) {
Node *head = NULL;
// head = create(0);
add (&head,0);
add (&head,1);
add (&head,2);
add (&head,3);
printf ("\nsearching:\n\n");
search (head);
printf ("\nprinting:\n\n");
printvalues (head);
return 0;
}
/* create - only creates nodes */
Node *create (int v)
{
Node *new;
new = calloc (1, sizeof *new);
new->value = v;
new->next = NULL;
return new;
}
/* add does NOT create - only handles wiring */
void add (Node **head, int v)
{
Node *new = create (v);
if (!*head) {
*head = new;
return;
}
Node *p = *head;
while (p && p->next)
p = p->next;
if (!(*head)->next)
(*head)->next = new;
else
p->next = new;
}
void search(Node *head)
{
Node *p = head;
while (p != NULL) {
printf (" address is %p; next address is %p;\n", p, p->next);
p = p->next;
}
}
void printvalues (Node *head)
{
Node *p = head;
unsigned cnt = 0;
while (p != NULL) {
printf (" node[%2u] value: %d\n", cnt++, p->value);
p = p->next;
}
}
Output
$ ./bin/dbgllmess
searching:
address is 0x1acf010; next address is 0x1acf030;
address is 0x1acf030; next address is 0x1acf050;
address is 0x1acf050; next address is 0x1acf070;
address is 0x1acf070; next address is (nil);
printing:
node[ 0] value: 0
node[ 1] value: 1
node[ 2] value: 2
node[ 3] value: 3
Note: you are responsible for freeing the memory allocated when it is no longer needed. Let me know if you have any questions.
Regarding the real question "why is every node's size in the heap is 16 bytes?"
Well, you can't expect that one memory block will lay exactly at the end of where the previous memory block sits. you can't assume anything about how the heap is managed intenally. two blocks can sit in a gigabyte distance from one another even if they allcoated consequently with malloc.
On Windows , In order for the heap to keep track of the memory blocks allocated, each block gets few more bytes to hold meta-data of the memory block. this is called "Heap Entry", and it is probably why your blocks are a bit bigger.
but again, you can't assume anything of the blocks - positioning in the heap anyway.
i'm trying to invert the "info" field of the in a list like the one below
struct nodo {
int info;
struct nodo *next;
struct nodo *prev;
} ;
typedef struct nodo nodo;
Here is the main, the two output should be the original list of n mebmers, and the inverted list (First value go n , second n-1 and so on)
int main(int argc, const char * argv[]) {
struct nodo *p;
p = CreateList();
PrintList(p);
IvertList(p);
Printlist(p);
return 0;
}
Here is InvertList(): (Count() function just returns dimension of the list, i know it is a messy way but i'm focused on result for now)
void InvertList (struct nodo *p) {
int tmp = 0, num = 0, i = 0;
num = (Count(p));
tmp = num;
for (i=1; i!=tmp; i++) {
Swap(p,num);
num--;
}
}
And here is Swap(), this should bring a value (int info) to the first place of the list, to the last swapping with each:
void Swap (struct nodo *p, int n) {
int *tmp1 = NULL, *tmp2 = NULL;
int i;
for ( i = 1; i != n && p != NULL; i++) {
tmp1 = &p->info;
p = p->succ;
tmp2 = &p->info;
p->info = *tmp1;
p->prec->info = *tmp2;
}
}
Now the output i got printed is:
Value: 1
Value: 2
Value: 3
Value: 4
Value: 5
Value: 1
Value: 1
Value: 1
Value: 1
Value: 1
Where the last 5 values should be 5-4-3-2-1.
The bug(s) in your code not withstanding, you're not reversing your physical list at all, which I can all-but-guarantee is the point of the exercise in the first place.
Inversion of a linked list means all the pointers switch directions and the old tail becomes the new head. You seem to be avoiding that and trying to swap node info values instead.
To invert your list using simple pointer swapping:
// note head pointer passed by address
void InvertList(node **pp)
{
node *cur = *pp;
while (cur)
{
node *tmp = cur->prev;
cur->prev = cur->next;
cur->next = tmp;
*pp = cur;
cur = cur->prev;
}
}
And invoke from main() as:
InvertList(&p);
Note that no info values need be swapped, copied, etc. The node pointers simply switch direction and their enumeration will start at the other end. A full working example appears below:
#include<stdio.h>
#include<stdlib.h>
struct node
{
int info;
struct node *next;
struct node *prev;
};
typedef struct node node;
static void PrintList(const node *head)
{
while (head)
{
printf("%d: this=%p, prev=%p, next=%p\n",
head->info, head, head->prev, head->next);
head = head->next;
}
}
static void InvertList(node **pp)
{
node *cur = *pp;
while (cur)
{
node *tmp = cur->prev;
cur->prev = cur->next;
cur->next = tmp;
*pp = cur;
cur = cur->prev;
}
}
int main()
{
node *prev = NULL, *head = NULL, **pp = &head;
for (int i=1; i<=5; ++i)
{
*pp = malloc(sizeof **pp);
(*pp)->info = i;
(*pp)->prev = prev;
prev = *pp;
pp = &(*pp)->next;
}
*pp = NULL;
PrintList(head); // prints 1,2,3,4,5
InvertList(&head);
PrintList(head); // prints 5,4,3,2,1
}
Output (addresses vary, obviously)
1: this=0x1001054b0, prev=0x0, next=0x1001054d0
2: this=0x1001054d0, prev=0x1001054b0, next=0x1001054f0
3: this=0x1001054f0, prev=0x1001054d0, next=0x100105510
4: this=0x100105510, prev=0x1001054f0, next=0x100105530
5: this=0x100105530, prev=0x100105510, next=0x0
5: this=0x100105530, prev=0x0, next=0x100105510
4: this=0x100105510, prev=0x100105530, next=0x1001054f0
3: this=0x1001054f0, prev=0x100105510, next=0x1001054d0
2: this=0x1001054d0, prev=0x1001054f0, next=0x1001054b0
1: this=0x1001054b0, prev=0x1001054d0, next=0x0
There is a bug in your Swap fcn:
p->info = *tmp1;
p->prev->info = *tmp2;
But what are tmp1 and tmp2 at that time? Well, after we advanced p, tmp1 points at p->prev->info, while tmp2 = &p->info; So we could rewrite these assignments in effect as:
p->info = p->prev->info;
p->prev->info = p->info;
So, we could rewrite them again, in effect, as:
p->info = p->prev->info;
p->prev->info = p->prev->info;
So, the second assignment doesn't change anything in effect. Therefore, the first call to Swap in InvertList takes the value of the first element (1) and sets all the values in the list equal to it. The subsequent calls to Swap act similarly but have no effect as the list already contains all 1's.
Here's a simple way to rewrite Swap:
void Swap(struct nodo *p, int n)
{
if (n <= 1)
return;
int tmp = p->info;
for (int i = 1; i != n; ++i, p = p->next)
p->info = p->next->info;
p->info = tmp;
}
Note, however, that the way you've written InvertList is doing theta(n^2) work. The first loop iteration shifts the first element n-1 spots, the second iteration shifts the first element n-2 spots, the third iteration shifts the first element n-3 spots, and so on, down to shifting the first element 1 spot. So, you end up doing something like n * (n - 1) / 2 total shifts to reverse the list.
A linked list can be reversed / inverted in theta(n) work. See if you can figure out a better way to do this. If you had a pointer to both the beginning and the end of the list (which you often want anyway), then you could do something similar to reversing the characters in a string, for example.
So I'm trying to implement a cache in C. I have included a very slimmed down version of my code.
I keep getting this error:
prog.c: In function ‘addtolist’:
prog.c:29: warning: assignment from incompatible pointer type
prog.c:40: warning: assignment from incompatible pointer type
prog.c: In function ‘main’:
prog.c:72: warning: assignment from incompatible pointer type
from this code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct node_
{
char * word;
int filenumber;
struct node * next;
};
typedef struct node_ * node;
node createnode()
{
node head;
head = malloc(sizeof(struct node_));
head->word = NULL;
head->next = NULL;
return head;
}
unsigned int addtolist(node head, char * word, unsigned int limit, int fileno)
{
unsigned int templimit = limit;
node temp;
node temphead = head;
while(temphead->next != NULL)
{
temphead = temphead->next;
}
temp = malloc(sizeof(struct node_));
temp->word =(char*) malloc(strlen(word)+ 1);
strcpy(temp->word, word);
temp->next = NULL;
temp->filenumber = fileno;
templimit = templimit - (strlen(word) + 1) - sizeof(struct node_)- sizeof(int);
printf("templimit is size %u\n", templimit);
if (templimit < limit && templimit > 0)
{
temphead->next = temp;
limit = limit - strlen(word) - 1 - sizeof(struct node_)- sizeof(int);
return limit;
}
else
{
free(temp->word);
free(temp);
return 0;
}
}
int main()
{
node newlist = createnode();
int i = 0;
unsigned int limit = 65;
unsigned int temp = limit;
while(temp > 0 && temp <= limit)
{
temp = addtolist(newlist, "Hello", temp, i);
i++;
printf("new limit is - \t%u\nfilenumber is - \t%d\n", temp,i);
}
node ptr = newlist;
while(ptr->next != NULL)
{
printf("node %d contains the word %s\n", ptr->filenumber, ptr->word);
ptr = ptr->next;
}
return 1;
}
I honestly can't figure out what I'm doing wrong... My logic was that, since I was typedef'ing my struct as a pointer, after I created the struct in memory, I would be able to easily step through the ensuing list. Where was the flaw in my logic?
EDIT the initial problem was fixed (I forgot an underscore in my type declaration for struct node_ next;.
Now I'm having another problem: when I try to step through the list at the bottom of my code to print out the words contained in the list, I'm basically not able to step through the list. I keep outputting:
templimit is size 43
new limit is - 43
filenumber is - 1
templimit is size 21
new limit is - 21
filenumber is - 2
templimit is size 4294967295
new limit is - 0
filenumber is - 3
node 0 contains the word (null)
node 0 contains the word Hello
For some reason, it seems that my program isn't storing my changes to my list in memory after the first iteration. Any ideas on what I'm doing wrong?
Once again, any help would be appreciated, and thanks.
Inside your structure definition you have struct node without the underscore.
you'd better have a forward declaration
typedef struct node node;
and then declare your structure
struct node {
...
node *next;
};
no need to have this underscore stuff and hiding the * in a typedef. That only makes you mix things up easily.
String literals "like this" have type const char*, not char*, because they're immutable.
Fix your declarations to have const char* and the warnings will go away.
I think the struct member 'next' has to be declared as a (node_ *) type. As written it is currently (node_ **)