How to get struct field having pointer to the struct? - c

I have two structs:
struct first
{
int* array;
}
struct second
{
struct first* firsts;
} *SECOND;
Let's say somewhere I can get the address of one of struct first from SECOND->firsts by its index.
How could I get array of this struct? I've tried
SECOND->firsts[index]->array
but there is expression must have pointer-to-struct-or-union type error.

No malloc checks and no free - just to show the idea
struct first {
int* array; };
struct second {
struct first* firsts; } *SECOND;
#define NUMFIRSTS 50
#define ARRSIZE 50
int main() {
SECOND = malloc(sizeof(*SECOND));
SECOND -> firsts = malloc(NUMFIRSTS * sizeof(*SECOND -> firsts));
for(int f = 0; f < NUMFIRSTS; f++)
{
SECOND -> firsts[f].array = malloc(ARRSIZE * sizeof(*SECOND -> firsts[f].array));
}
//access
SECOND -> firsts[5].array[10] = 23;
}

Here you are.
#include <stdio.h>
#include <stdlib.h>
struct first
{
int* array;
};
struct second
{
struct first* firsts;
} *SECOND;
int main(void)
{
size_t n = 10;
struct first f = { NULL };
SECOND = malloc( sizeof( *SECOND ) );
SECOND->firsts = &f;
SECOND->firsts->array = malloc( n * sizeof( int ) );
for ( size_t i = 0; i < n; i++ )
{
SECOND->firsts->array[i] = ( int )i;
}
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", SECOND->firsts->array[i] );
}
putchar( '\n' );
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", f.array[i] );
}
putchar( '\n' );
// ...
// free all allocated memory
return 0;
}
the program output is
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
Pay attention to that as the pointer SECOND contains pointer to struct first f that in turn contains pointer to array then the both objects points to the same memory pointed to by the pointer array.

The array index operator [] has an implicit pointer dereference. So this expression:
SECOND->firsts[index]
Has type struct first, not struct first *, which means you can't use the -> operator on it. You need to instead use the member selector operator .:
SECOND->firsts[index].array

Related

How to correctly initialise a struct in C

I'm working on a small project in C and I want to allocate structs in a function and add them to an array of structs.
For some reason, when I go to print the contents of the array of structs, I appear to start printing from unallocated memory.
A minimum working example is provided below:
#include <stdio.h>
#include <stdlib.h>
// This struct simply stores a list and its size
struct list {
int* values;
size_t size;
};
// This function initialises an array of lists
// of size len, which each list (i.e. list.values)
// having a size of list_len
// `lists` is an array of pointers to lists
void list_init(struct list** lists, size_t len, size_t list_len) {
for (size_t i = 0; i < len; i++) {
struct list list;
list.values = malloc(sizeof(int) * list_len);
list.size = list_len;
lists[i] = &list;
}
}
void main() {
int len = 3;
struct list* lists[len];
list_init(lists, len, 5);
// Print lists
for (size_t i = 0; i < len; i++) {
printf("list %zu: ", i);
printf("size: %zu\n", lists[i]->size);
for (size_t j = 0; j < 5; j++) { // Using 5 instead of lists[i]->size for obvious reasons
printf("%d ", lists[i]->values[j]);
}
printf("\n");
}
}
The output I would expect from this is:
list 0: size: 5
0 0 0 0 0
list 1: size: 5
0 0 0 0 0
list 2: size: 5
0 0 0 0 0
but instead I get:
list 0: size: 5
0 0 0 0 0
list 1: size: 140727488332736
0 0 0 0 0
list 2: size: 140727488332736
0 0 0 0 0
which is a pretty clear sign that I'm accessing memory that I'm not supposed to.
I noticed that rather than declaring the list with struct list list;, if I declare the list by allocating memory to a pointer with struct list* list = malloc(sizeof(struct list)); the program gives the expected output. Why is that? If I want to create the object, rather than a pointer, how can I do that properly.
P.S.: I am aware that I could just initialise list as a pointer. This question is mostly asking why can't I initialise it as an object
You save the references to the same local variable and it is an UB. Also malloced memory is lost. Your main is also wrong.
I would do it this way (calloc is used as in main you print not initialized allocated memory):
typedef struct list {
size_t size;
int values[];
}list;
list **list_init(list **array, size_t size, size_t list_len)
{
list **wrk;
if(!array) wrk = malloc(sizeof(*wrk) * size);
else wrk = array;
if(wrk)
for (size_t i = 0; i < size; i++) {
list *list = calloc(1, sizeof(*list) + list_len * sizeof(list -> values[0]));
/* check for allocation errors!!!! */
list -> size = list_len;
wrk[i] = list;
}
return wrk;
}
int main(void) {
size_t len = 3;
list **lists;
/* if you pass NULL it will create the list of lists itself */
lists = list_init(NULL, len, 5);
/* check for allocation errors!!!! */
// Print lists
for (size_t i = 0; i < len; i++) {
printf("list %zu: ", i);
printf("size: %zu\n", lists[i]->size);
for (size_t j = 0; j < 5; j++) { // Using 5 instead of lists[i]->size for obvious reasons
printf("%d ", lists[i]->values[j]);
}
printf("\n");
}
for (size_t i = 0; i < len; i++) free(lists[i]);
free(lists);
}
https://godbolt.org/z/9TPe1sM1a
These statements within the function list_init
struct list list;
//...
lists[i] = &list;
does not make a sense because the local object list will not be alive after exiting the function. So you will have an array of invalid pointers of the type struct list *.
You need to allocate dynamically each object of the type struct list that will be pointed to by an element of the array.
The function can be declared and defined for example the following way
size_t list_init( struct list **lists, size_t len, size_t list_len )
{
size_t count = 0;
for ( size_t i = 0; i < len; i++ )
{
lists[i] = malloc( sizeof( struct list ) );
if ( lists[i] != NULL )
{
++count;
lists[i]->size = 0;
lists[i]->values = malloc( sizeof( int ) * list_len );
if ( lists[i]->values != NULL ) lists[i]->size = list_len;
}
}
return count;
}
Also as the function does not initialize the allocated array pointed to by the data member values then this loop in main
for (size_t j = 0; j < 5; j++) { // Using 5 instead of lists[i]->size for obvious reasons
printf("%d ", lists[i]->values[j]);
}
will invoke undefined behavior.
You could zero initialize the arras by using calloc instead of malloc. For example
lists[i]->values = calloc( list_len, sizeof( int ) );
And pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )
Here is your updated program.
#include <stdio.h>
#include <stdlib.h>
// This struct simply stores a list and its size
struct list
{
int* values;
size_t size;
};
size_t list_init( struct list **lists, size_t len, size_t list_len )
{
size_t count = 0;
for ( size_t i = 0; i < len; i++ )
{
lists[i] = malloc( sizeof( struct list ) );
if ( lists[i] != NULL )
{
++count;
lists[i]->size = 0;
lists[i]->values = calloc( list_len, sizeof( int ));
if ( lists[i]->values != NULL ) lists[i]->size = list_len;
}
}
return count;
}
int main(void)
{
size_t len = 3;
struct list* lists[len];
list_init(lists, len, 5);
// Print lists
for ( size_t i = 0; i < len; i++ )
{
printf( "list %zu: ", i );
if ( lists[i] != NULL )
{
printf( "size: %zu\n", lists[i]->size );
for (size_t j = 0; j < lists[i]->size; j++)
{
printf( "%d ", lists[i]->values[j] );
}
printf("\n");
}
}
return 0;
}
The program output is
list 0: size: 5
0 0 0 0 0
list 1: size: 5
0 0 0 0 0
list 2: size: 5
0 0 0 0 0
Of course you need to add a code to your program that will free all the allocated memory in the function list_init.

free() in dynamic memory

Do I use correctly free() in the code below? Is it a memory leak? Is it a problem use free() in the main part and not in the function? If yes there is a method to free in the function and not in main?
This code copy an array in another one.
int *copy(const int *arr,int n);
int main(){
int *p_arr1,*p_arr2;
int n,i;
printf("Insert size of array: ");
scanf("%d",&n);
p_arr1 = calloc(n,sizeof(int));
for(i=0;i<n;i++){
printf("Insert element %d of the array: ",i+1);
scanf("%d",p_arr1+i);
}
p_arr2 = copy(p_arr1,n);
for(i=0;i<n;i++){
printf("%d ",*p_arr2);
p_arr2++;
}
free(p_arr1);
free(p_arr2);
return 0;
}
int *copy(const int *arr,int n){
int i;
int *new;
new = calloc(n, sizeof(int));
for(i=0;i<n;i++){
new[i] += arr[i];
}
return new;
}
As long as you have the pointer returned by malloc (or in your case calloc) you can pass it to free when and wherever you want, it doesn't have to be in the same function.
However, after the loop where you print the contents of p_arr2, you no longer have the pointer returned by calloc inside the function, because you modify the pointer in the loop.
You need to use a temporary pointer variable for the loop:
int *p_arr2_tmp = p_arr2;
for (size_t i = 0; i < n; ++i)
{
printf("%d ", *p_arr2_tmp);
++p_arr2_tmp;
}
// Now we can free the memory pointed to by the original p_arr2 pointer
free(p_arr2);
Or you could use simple array indexing instead:
for (size_t i = 0; i < n; ++i)
{
printf("%d ", p_arr2[i]);
}
// The pointer p_arr2 wasn't modified, so it can be passed to free
free(p_arr2);
In this loop
for(i=0;i<n;i++){
printf("%d ",*p_arr2);
p_arr2++;
}
the value of the pointer p_arr2 is being changed, So using the changed pointer in a call of free results in undefined behavior.
You should write
for(i=0;i<n;i++){
printf("%d ", p_arr2[i] );
}
Also it is unclear why you are using the compound operator += in the function instead of the operator =.
new[i] += arr[i];
The function can be defined the following way
int * copy( const int *arr, size_t n )
{
int *new_arr = malloc( n * sizeof( int ) );
if ( new_arr != NULL )
{
memcpy( new_arr, arr, n * sizeof( int ) );
}
return new_arr;
}
If you want to use a pointer in the loop that outputs the newly created array then it can look the following way
for ( const int *p = p_arr2; p != p_arr2 + n; ++p )
{
printf( "%d ",*p );
}
putchar( '\n' );
If the aim is to write a program that uses only pointers and excludes using of the subscript operator and indices then your program can look the following way
#include <stdio.h>
#include <stdlib.h>
int * copy( const int *arr, size_t n )
{
int *new_arr = malloc( n * sizeof( int ) );
if ( new_arr != NULL )
{
for ( int *p = new_arr; p != new_arr + n; ++p )
{
*p = *arr++;
}
}
return new_arr;
}
int main(void)
{
size_t n;
printf( "Insert size of array: " );
scanf( "%zu", &n );
int *p_arr1 = calloc( n, sizeof( int ) );
for ( int *p = p_arr1; p != p_arr1 + n; ++p )
{
printf( "Insert element %d of the array: ", ( int )( p - p_arr1 + 1 ) );
scanf( "%d", p );
}
int *p_arr2 = copy( p_arr1, n );
if ( p_arr2 != NULL )
{
for ( const int *p = p_arr2; p != p_arr2 + n; ++p )
{
printf( "%d ",*p );
}
putchar( '\n' );
}
free( p_arr2 );
free( p_arr1 );
return 0;
}
The program output might look like
Insert size of array: 10
Insert element 1 of the array: 0
Insert element 2 of the array: 1
Insert element 3 of the array: 2
Insert element 4 of the array: 3
Insert element 5 of the array: 4
Insert element 6 of the array: 5
Insert element 7 of the array: 6
Insert element 8 of the array: 7
Insert element 9 of the array: 8
Insert element 10 of the array: 9
0 1 2 3 4 5 6 7 8 9

Add an adress to an array of pointers C

I have to write a function that will add an adress at the end of an array of pointers. Here is what I've done. I want to know if I did right and if not, please correct me.
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
void add( int *array[MAX], int *addr)
{
array = realloc(array, 1*sizeof(int));
array[MAX+1] = addr;
}
int main()
{
int *addr = 4;
int *array[MAX] = {"1","2","3"};
add(array, addr);
int i;
for(i = 0; i<4;i++)
printf("%d ", array[i]);
return 0;
}
from the manual for realloc:
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
initialized. 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.
if its too long to read ill explain.
first of all you should use realloc after allocating memory ( using malloc for example ) and not after local declaration
second you're treating pointers to int ( int * ) as if they we're int. also shown as warning
examples:
int *addr = 4;
int *array[MAX] = {"1","2","3"};
array = realloc(array, 1*sizeof(int)); // here you're using sizeof( int )
another problem is reaching out of bound of array
array[MAX+1] = addr;
for an array with 3 spaces - you have array[ 0 ], array[ 1 ] and array[ 2 ].
in this line you're trying to reach the array[ 4 ] of an array ( that's suppose to be ) of size 4 --> out of bounds
my suggested code for this will be:
code edited
#include <stdio.h>
#include <stdlib.h>
#define MAX 3
void add( int **array[ MAX ], int *addr )
{
*array = realloc( *array, ( MAX + 1 ) * sizeof( int* ) );
(*array)[ MAX ] = addr;
}
int main()
{
int i;
int *addr;
int **array;
addr = &i;
array = malloc( MAX * sizeof ( int* ) );
for ( i = 1; i <= MAX; i++ ) {
array[ i - 1 ] = addr + 4 * i;
}
add( &array, addr );
for ( i = 0; i < MAX + 1; i++ ) {
printf( "%p ", array[ i ] );
}
return 0;
}

Pointer to Pointer to a structure in c

I have a simple structure.
struct grades
{
int lowest;
int highest;
};
Then I am to create a function that returns a pointer which initializes the structure.
struct *grades setGrades(int low, int high)
{
struct *ptr = malloc(sizeof(struct grades));
ptr->lowest = low;
ptr->highest = high;
return ptr;
}
Now I am supposed to make a function with definition struct **grades random(int size);
I am supposed to allocate space for an array of pointers to grade structures with the number of elements equal to size. When the array of pointers is created, I want to set each pointer in the array to a newly created data structure that has the low variable equal to 10 and high variable equal to 100 and then return pointer.
I am really lost at this point as I looked up double pointers to structures online but did not find any examples that can help me clear my understanding. I was wondering if someone can perhaps explain me how double pointers to structures work it would give me a Great start in the right directions.
A "double pointer" as you called it is simply a pointer to a pointer. That is, struct grade example is a variable that contains a lowest and a highest as you've defined. A pointer to that, struct grade *example is a variable that stores the memory address of the same structure. A pointer to a pointer, struct grade **example, is a variable that stores the memory address of a variable that stores the memory address of your structure. A more detailed explanation can be found here. Anyways, to answer your specific question, a function would be:
struct grades** random(int size) {
struct grades** result = malloc(sizeof(struct grades*) * size); //here you are
//allocating enough space for an
//array of pointers
int i;
for(i = 0; i < size; i++) {
result[i] = setGrades(10, 100); //here you are setting each pointer to one
//grade through the function you've already
//defined
}
return result;
}
struct grades { int lowest; int highest; };
struct grades * createGradeSet(int low, int high) //careful: return type is struct grades *
{
// variable name: ptr, type: struct grades *
struct grades * ptr = malloc(sizeof(struct grades));
ptr->lowest = low;
ptr->highest = high;
return ptr;
}
struct grades ** random(int size)
{
// Create a pointer to an array of struct grades pointers
// the size of the array is `size` x the size of a struct grades pointer
struct grades ** ptr_arr = malloc(sizeof(struct grades *) * size);
for (unsigned int i = 0; i < size; i++)
ptr_arr[i] = createGradeSet(10, 100); // assign a newly created Gradeset to every cell
return ptr_arr;
}
Try the following
struct grades ** random( size_t size )
{
if ( size == 0 ) return NULL:
struct grades **p = malloc( size * sizeof( struct grades * ) );
if ( p != NULL )
{
size_t i = 0;
do
{
p[i] = malloc( sizeof( struct grades ) );
if ( p[i] != NULL )
{
p[i]->lowest = 10;
p[i]->highest = 100;
}
} while ( p[i] != NULL && ++i < size );
if ( i != size )
{
for ( size_t j = 0; j < i; j++ ) free( p[i] );
}
free( p );
p = NULL;
}
return p;
}
Function setGrades should be written as
struct *grades setGrades( int low, int high )
{
struct *p = malloc( sizeof( struct grades ) );
if ( p != NULL )
{
p->lowest = low;
p->highest = high;
}
return p;
}
In this case the do while loop in the above function can be written as
do
{
p[i] = setGrades( 10, 100 );
} while ( p[i] != NULL && ++i < size );

2D pointer arithmetic in C

I am attempting to swap 2 elements in a 2D array in C, with no luck.
Thanks for the answers so far, but I have edited this code to make things clearer about what I am doing.
typedef struct smystruct { /* stuff... */ } mystruct;
void nswap( mystruct ** a, mystruct ** b )
{
mystruct * tmp = *a;
*a = *b;
*b = tmp;
}
void nqsort( mystruct ** h, int m, int n )
{
double key = 0.0;
int i = 0, j = 0, k = 0;
if( m < n ) {
// choose the pivot point...
k = (m + n) / 2;
nswap( &h[ n ], &h[ k ] );
key = (*h+m)->prob;
i = m + 1;
j = n;
while ( i <= j ) {
while ( (i <= n) && (*h+i)->prob <= key )
i++;
while ( (j >= m) && (*h+j)->prob > key )
j--;
if ( i < j ) {
nswap( &h[i], &h[j] );
}
}
// swap two elements
nswap( &h[m], &h[j] );
// recursively sort the lesser list
nqsort( h, m, j-1 );
nqsort( h, j+1, n );
}
}
int main()
{
mystruct * p = NULL;
// get the number of nodes (m)...
fscanf( in, "%d", &m );
// allocate memory for the node and connectivity matrix arrays...
p = (mystruct*)malloc( sizeof( mystruct ) * m );
// read in the location and associated probabilities!...
for ( ; loop < m ; ++loop ) {
mystruct * tmpnode = p + loop;
tmpnode->str = (char*)malloc( sizeof( char ) * 1024 );
fscanf( in, "%s %lf", (char *)tmpnode->str, &tmpnode->prob );
}
nqsort( &p, 0, m );
}
Needless to say this does not work. I have searched for examples and nothing seems to work. Advise for the n00b would be appreciated.
The last element has index count-1, not count.
h[0] h[1] h[2] h[3] h[4] h[5] h[6] h[7] h[8] h[9]
----------------------------------------------------------
total 10 elements
I don't know what is fwnodes, perhaps you mean h.
Multiple stuff is wrong there.
1/ Your 2D array is badly allocated (or code is missing).
2/ A proper way to do such 2D allocation is to use Iliffe pointer (as advised in Numrical Recipes in C/C++).
mystruct** alloc_array( int h, int w )
{
int i;
mystruct** m = malloc(h*sizeof(mystruct*));
m[0] = malloc(h*w*sizeof(mystruct));
for(i=1;i<h;i++) m[i] = m[i-1]+w;
return m;
}
void release_array(mystruct** m)
{
free( m[0] );
free( m);
}
This way of allocating brings you both a contiguous block of memory (which is easier to handle, is more cache friendly, dont require to do some index computation) and a [][] access.
Your swap function then become :
void swap( mystruct* a, mystruct* b )
{
mystruct tmp = *a
*a = *b;
*b = tmp;
}
and can be called like :
swap( &some_tab[i][j], &some_other_tab[u][v] );
In a full example :
int main()
{
mystruct** my_array = alloc_array(3,4); /* 3x4 mystruct array */
/* fill the array */
/* Swap some */
swap( &my_array[2][1], &my_array[0][3] );
release_array(my_array);
}
You are passing pointer to array to your function. That means h has only one element.
swap( &p, 10 );
Should be:
swap( p, 10 );
That means you need to change your function to accept arrays of mystruct or change p to array of pointers to mystruct.
And, as KennyTM suggested the last element has index 9 not 10.

Resources