A link is a pointer to a node
typedef struct node * link;
In main(), I have the following code (config->m is just some integer):
// array of pointers to structs
link heads[config->m];
// make memory for head nodes
for(i = 0; i < config->m; i++)
heads[i] = malloc(sizeof(struct node));
The code works (which is great). But is there a way I can allocate config->m pieces of memory without the loop? I tried
link heads[config->m];
heads = malloc(sizeof(struct node) * config->m);
but my friendly neighborhood compiler tells me incompatible types in assignment
I know I could use
struct node heads[config->m];
But I want to do this stuff with pointers.
And as always, someone will ask me if this is part of homework, and the answer is yes (sort of). But this particular chunk of code doesn't have anything to do with the actual assignment; it's for my own enlightenment. But thanks for asking :|
Nope, you need the loop. Your heads array is essentially a two dimensional array. You need at least two allocations. The first is the array of pointers:
link * heads = (link*)malloc (config->m * sizeof (link));
The second is the memory that each member of the heads array points to:
link buf = (link)malloc(sizeof(struct node) * config->m);
for(i = 0; i < config->m; i++)
heads[i] = &buf[i];
And then to de-allocate:
free(heads);
free(buf);
link heads[config->m];
link buffer = malloc(sizeof(struct node) * config->m);
for(i = 0; i < config->m; i++)
heads[i] = &buffer[i];
....
free(buffer);
On edit:
Actually, you don't need heads. First, let's get rid of link, as (see comments in Cannonade's answer) it just confuses the issue.
Let's pretend that a struct node is a node in an intrusive linked list, and looks like this:
struct node {
int val;
int filler[10]; // this is pure filler, to make node big
struct node* next;
};
Now we add our includes, and config->m:
#include <stdio.h>
#include <stdlib.h>
// your config->m
const int m = 10 ;
And in main() we print the sizeof a node:
int main() {
printf( "sizeof( struct node ) = %i\n", sizeof( struct node) );
Now we declare a pointer to node:
// na is a node pointer
struct node* na;
And malloc up m nodes. malloc returns the address of the array, whichis also the address of the first node in the array. We set na to the address malloc returned:
na = malloc(sizeof(struct node) * m);
Now we will use na, a pointer, as if it were an array. This works because C defines array[offset] as *(array + offset * sizeof(element))
int i;
// we give the first node a val of zero
na[0].val = 0;
// and a null next pointer
na[0].next = 0 ;
Now we'll walk up the rest of the array and set each node's next to the PREVIOUS node in the array:
for(i = 1; i < m; i++) {
na[i].val = i ;
// na[ offset ] is *(na + offset)
// we don't want to dereference,
// we want the address, so we use the
// address-of operator ("&")
na[i].next = &na[ i - 1 ];
}
Our head is the LAST node in the array na[ m - 1]. Each next in the list is the preceding node in the array. Again, we use the address-of operator if we want the pointer, instead of what's pointed to:
struct node* current = &na[ m - 1 ];
We'll print the address of each node. It should be the address of its next node pointer + sizeof( struct node), because each node is the node after (in the array) its next in the list ( the list is the array "reversed").
We cast it to char* to get a result in bytes. If we don't cast, we get the result in units of truct node* (which should always be 1).
while( current ) {
printf( "val %i, address of current %p, ", current->val, current) ;
printf( " address of current->next %p, ", current->next ) ;
if( current->next ) {
printf( " distance from next: ");
printf( "in bytes %i, ",
( (char*) current) - (char*) current->next ) ;
printf( " in struct nodes %i", current - current->next ) ;
}
printf( "\n" );
current = current->next;
}
return 0;
}
On my system, that gives this output:
sizeof( struct node ) = 48
val 9, address of current 0x804a1b8, address of current->next 0x804a188, distance from next: in bytes 48, in struct nodes 1
val 8, address of current 0x804a188, address of current->next 0x804a158, distance from next: in bytes 48, in struct nodes 1
val 7, address of current 0x804a158, address of current->next 0x804a128, distance from next: in bytes 48, in struct nodes 1
val 6, address of current 0x804a128, address of current->next 0x804a0f8, distance from next: in bytes 48, in struct nodes 1
val 5, address of current 0x804a0f8, address of current->next 0x804a0c8, distance from next: in bytes 48, in struct nodes 1
val 4, address of current 0x804a0c8, address of current->next 0x804a098, distance from next: in bytes 48, in struct nodes 1
val 3, address of current 0x804a098, address of current->next 0x804a068, distance from next: in bytes 48, in struct nodes 1
val 2, address of current 0x804a068, address of current->next 0x804a038, distance from next: in bytes 48, in struct nodes 1
val 1, address of current 0x804a038, address of current->next 0x804a008, distance from next: in bytes 48, in struct nodes 1
val 0, address of current 0x804a008, address of current->next (nil),
Related
I have a block of pointers to some structs which I want to handle (i.e. free) separately. As an example below there is an integer double-pointer which should keep other pointers to integer. I then would like to free the second of those integer pointers (in my program based on some filterings and calculations). If I do so however, I should keep track of int-pointers already set free so that when I iterate over the pointers in the double-pointer I do not take the risk of working with them further. Is there a better approach for solving this problem (in ANSI-C) without using other libs (e.g. glib or alike)?
Here is a small simulation of the problem:
#include <stdio.h>
#include <stdlib.h>
int main() {
int **ipp=NULL;
for (int i = 0; i < 3; i++) {
int *ip = malloc(sizeof (int));
printf("%p -> ip %d\n", ip, i);
*ip = i * 10;
if ((ipp = realloc(ipp, sizeof (int *) * (i + 1)))) {
ipp[i] = ip;
}
}
printf("%p -> ipp\n", ipp);
for (int i = 0; i < 3; i++) {
printf("%d. %p %p %d\n", i, ipp + i, *(ipp+i), **(ipp + i));
}
// free the middle integer pointer
free(*(ipp+1));
printf("====\n");
for (int i = 0; i < 3; i++) {
printf("%d. %p %p %d\n", i, ipp + i, *(ipp+i), **(ipp + i));
}
return 0;
}
which prints something like
0x555bcc07f2a0 -> ip 0
0x555bcc07f6f0 -> ip 1
0x555bcc07f710 -> ip 2
0x555bcc07f6d0 -> ipp
0. 0x555bcc07f6d0 0x555bcc07f2a0 0
1. 0x555bcc07f6d8 0x555bcc07f6f0 10
2. 0x555bcc07f6e0 0x555bcc07f710 20
====
0. 0x555bcc07f6d0 0x555bcc07f2a0 0
1. 0x555bcc07f6d8 0x555bcc07f6f0 0
2. 0x555bcc07f6e0 0x555bcc07f710 20
Here I have freed the middle int-pointer. In my actual program I create a new block for an integer double-pointer, iterate over the current one, create new integer pointers and copy the old values into it, realloc the double-pointer block and append the new pointer to it, and at the end free the old block and all it's containing pointers. This is a bit ugly, and resource-consuming if there is a huge amount of data, since I have to iterate over and create and copy all the data twice. Any help is appreciated.
Re:
"This is a bit ugly, and resource-consuming if there is a huge amount of data, since I have to iterate over and create and copy all the data
twice. Any help is appreciated."
First observation: It is not necessary to use realloc() when allocating new memory on a pointer that has already been freed. realloc() is useful when needing to preserve the contents in a particular area of memory, while expanding its size. If that is not a need (which is not in this case) malloc() or calloc() are sufficient. #Marco's suggestion is correct.
Second observation: the following code snippet:
if ((ipp = realloc(ipp, sizeof (int *) * (i + 1)))) {
ipp[i] = ip;
}
is a potential memory leak. If the call to realloc()_ fails, the pointer ipp will be set to null, making the memory location that was previously allocated becomes orphaned, with no way to free it.
Third observation: Your approach is described as needing:
Array of struct
dynamic memory allocation of a 2D array
need to delete elements of 2D array, and ensure they are not referenced once deleted
need to repurpose deleted elements of 2D array
Your initial reaction in comments to considering using an alternative approach notwithstanding, Linked lists are a perfect fit to address the needs stated in your post.
The fundamental element of a Linked List uses a struct
Nodes (elements) of a List are dynamically allocated when created.
Nodes of a List are not accessible to be used once deleted. (No need to track)
Once the need exists, a new node is easily created.
Example struct follows. I like to use a data struct to contain the payload, then use an additional struct as the conveyance, to carry the data when building a Linked List:
typedef struct {//to simulate your struct
int dNum;
char unique_name[30];
double fNum;
} data_s;
typedef struct Node {//conveyance of payload, forward and backward searchable
data_s data;
struct Node *next; // Pointer to next node in DLL
struct Node *prev; // Pointer to previous node in DLL
} list_t;
Creating a list is done by creating a series of nodes as needed during run-time. Typically as records of a database, or lines of a file are read, and the elements of the table record (of element of the line in a file) are read into and instance of the data part of the list_s struct. A function is typically defined to do this, for example
void insert_node(list_s **head, data_s *new)
{
list_s *temp = malloc(sizeof(*temp));
//insert lines to populate
temp.data.dNum = new.dNum;
strcpy(temp.data.unique_name, new.unique_name);
temp.fNum = new.fNum
//arrange list to accomdate new node in new list
temp->next = temp->prev = NULL;
if (!(*head))
(*head) = temp;
else//...or existing list
{
temp->next = *head;
(*head)->prev = temp;
(*head) = temp;
}
}
Deleting a node can be done in multiple ways. It the following example method a unique value of a node member is used, in this case unique_name
void delete_node_by_name(list_s** head_ref, const char *name)
{
BOOL not_found = TRUE;
// if list is empty
if ((*head_ref) == NULL)
return;
list_s *current = *head_ref;
list_s *next = NULL;
// traverse the list up to the end
while (current != NULL && not_found)
{
// if 'name' in node...
if (strcmp(current->data.unique_name, name) == 0)
{
//set loop to exit
not_found = FALSE;
//save current's next node in the pointer 'next' /
next = current->next;
// delete the node pointed to by 'current'
delete_node(head_ref, current);
// reset the pointers
current = next;
}
// increment to next node
else
{
current = current->next;
}
}
}
Where delete_node() is defined as:
void delete_node(list_t **head_ref, list_t *del)
{
// base case
if (*head_ref == NULL || del == NULL)
return;
// If node to be deleted is head node
if (*head_ref == del)
*head_ref = del->next;
// Change next only if node to be deleted is NOT the last node
if (del->next != NULL)
del->next->prev = del->prev;
// Change prev only if node to be deleted is NOT the first node
if (del->prev != NULL)
del->prev->next = del->next;
// Finally, free the memory occupied by del
free(del);
}
This link is an introduction to Linked Lists, and has additional links to other related topic to expand the types of lists that are available.
You could use standard function memmove and then call realloc. For example
Let's assume that currently there are n pointers. Then you can write
free( *(ipp + i ) );
memmove( ipp + i, ipp + i + 1, ( n - i - 1 ) * sizeof( *pp ) );
*( ipp + n - 1 ) = NULL; // if the call of realloc will not be successfull
// then the pointer will be equal to NULL
int **tmp = realloc( ipp, ( n - 1 ) * sizeof( *tmp ) );
if ( tmp != NULL )
{
ipp = tmp;
--n;
}
else
{
// some other actions
}
I have a small program got from this link which pushes element into the stack.On careful examination I see that the storage space taken by this next pointer in the program for the first value ,second value,and third value is different.Can anyone please give me a satisfactory explanation for why it is happening like this.
I am using gcc compiler
#include <stdlib.h>
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
int push_front( struct Node **head, int data )
{
struct Node *tmp = malloc( sizeof( struct Node ) );
int success = tmp != NULL;
if ( success )
{
tmp->data = data;
tmp->next = *head;
*head = tmp;
printf("\nAddress of pointer head now is %p for value %d",*head,data);
}
return success;
}
int main( void )
{
struct Node *head;
for ( int i = 0; i != 10; i++ ) push_front( &head, i );
return 0;
}
=======================================================================
output
-----
Address of pointer head now is 0x16f1010 for value 0
Address of pointer head now is 0x16f1440 for value 1
Address of pointer head now is 0x16f1460 for value 2
Address of pointer head now is 0x16f1480 for value 3
Address of pointer head now is 0x16f14a0 for value 4
Address of pointer head now is 0x16f14c0 for value 5
Address of pointer head now is 0x16f14e0 for value 6
Address of pointer head now is 0x16f1500 for value 7
Address of pointer head now is 0x16f1520 for value 8
Address of pointer head now is 0x16f1540 for value 9
The expectation is such that the header pointer should take equal bytes of address space while inserting each value.
malloc is used to dynamically allocate a contiguous block of memory of a given size. This memory is allocated from the heap.
malloc makes no guarantees that the memory allocated between two subsequent calls to malloc be contiguous.
For part of my C data structures assignment, I am tasked with taking an array of pointers to nodes of 2 doubly linked lists (one representing the main service queue, and the other representing a "bucket" of buzzers ready to be reused or used for the first time in the queue), doubling the size, while keeping the original contents in tact. The idea is that each node has an ID associated which corresponds to the number index of the pointer array map. So for example, the pointer in index 3 will always point to the node whose ID is 3. The boolean inQ is for something unrelated to this issue.
I've written most of the code, but it seems to be functioning incorrectly (it changes all the original pointers to the last node in the list before the array resizing) So, since the starting size of the array is 10 elements, when I print out the contents after the function, it displays 9 9 9 9 9 9 9 9 9 9.
Here are the structs im using:
typedef struct node {
int id;
int inQ;
struct node *next;
struct node *prev;
}NODE;
typedef struct list
{
NODE *front;
NODE *back;
int size;
} LIST;
//referred to as SQ in the separate header file
struct service_queue
{
LIST *queue;
LIST *bucket;
NODE **arr;
int arrSize;
int maxID;
};
Here is the function in question:
SQ sq_double_array(SQ *q)
{
NODE **arr2 = malloc(q->arrSize * 2 * sizeof(NODE*));
int i;
//fill the first half of the new array with the node pointers of the first array
for (i = 0; i < q->arrSize; i++)
{
arr2[i] = malloc(sizeof(NODE));
if (i > 0)
{
arr2[i - 1]->next = arr2[i];
arr2[i]->prev = arr2[i - 1];
}
arr2[i]->id = q->arr[i]->id;
arr2[i]->inQ = q->arr[i]->inQ;
arr2[i]->next = q->arr[i]->next;
arr2[i]->prev = q->arr[i]->prev;
}
//fill the second half with node pointers to the new nodes and place them into the bucket
for (i = q->arrSize; i < q->arrSize * 2; i++)
{
//Point the array elements equal to empty nodes, corresponding to the inidicies
arr2[i] = malloc(sizeof(NODE));
arr2[i]->id = i;
arr2[i]->inQ = 0;
//If the bucket is empty (first pass)
if (q->bucket->front == NULL)
{
q->bucket->front = arr2[i];
arr2[i]->prev = NULL;
arr2[i]->next = NULL;
q->bucket->back = arr2[i];
}
//If the bucket has at least 1 buzzer in it
else
{
q->bucket->back = malloc(sizeof(NODE));
q->bucket->back->next = arr2[i];
q->bucket->back = arr2[i];
q->bucket->back->next = NULL;
}
}
q->arrSize *= 2;
q->arr = arr2;
return *q;
}
Keep in mind this must only be done in c, which is why im not using 'new'
You could use the realloc function:
void *realloc(void *ptr, size_t size);
Quoted from the man pages:
The realloc() function changes the size of the memory block pointed to
by ptr to size bytes. The
contents will be unchanged in the range from the start of the region up to the minimum of the old
and new sizes. If the new size is larger than the old size, the added memory will not be initialā
ized. If ptr is NULL, then the call is equivalent to malloc(size), for all values of size; if
size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr). Unless ptr
is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If the
area pointed to was moved, a free(ptr) is done.
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.
We're trying to set the address of a struct to an address we are given but when we print out the address of the struct it seems to not be the same value as the address we are given.
/*a struct to keep block information*/
struct header{
int space;
int free; /* 1 = free space and 0 = full*/
struct header *nextHead;
struct header *prevHead;
};
typedef struct header node;
int myinit(int *array, int size){
int newSize = size;
node * nullPointer;
nullPointer = NULL; //make intermediatry node pointer for some bullshit reason
* (array) = newSize; /*store the size of the malloc at the first address*/
printf("Address : %p\n", &array[0]);
array++;
printf("Address after: %p\n", &array[0]);
/*initial block*/
node *root = (node *)&array; /*store the root at the next address available*/
printf("size of struct %lu\n", sizeof(struct header));
printf("%p\n", root);
root->space = newSize;
root->free = 1;
root->nextHead = nullPointer;
root->prevHead = nullPointer;
}
In the line
node *root = (node *)&array;
You're taking the address of "array" local variable. IOW, you take the address of value that's on the stack, not what you are expecting. You have to modify the function's signature like this:
int mymain(int **myarray, int size);
and modify its definition accordingly. Then, you can write:
node *root = (node *)array;
node *root = (node *)&array;
Here you obtain address of a pointer and cast it to other pointer. You should not do this. Here you must allocate the memory for the node:
node * root = (node *) malloc(sizeof(node));
// or this allocates the memory and puts zeros to it
node * root = (node *) calloc(1, sizeof(node));
Also, you don't need any nodes which points to NULL, you can simply use NULL like this:
node->nextHeader = NULL;
Also, instead of using &array[0], use array in this piece of code.
You will become less confused with pointers if you keep to simple code and understand every line you write. When you have a lot of ampersands and special signs in one line you're probably doing something wrong, train your spider sense for those situations.