CrispyCashew
CrispyCashew

Reputation: 101

Typecast void pointer to int and string

What I'm trying to do is store values in a array of Element struczs (that has a member void* data)

typedef struct {
void* data
} Element;

I have malloc'd the array to have 3 elements

Element* array = malloc(3 * sizeof(Element));

I know you can do it like this if data is a int but how do you do it if data is void *

array[0].data = 65;

I've tried typecasting

((*int)(array[0].data)) = 65;

but I get the message expected expression before 'int'

My second question is how would I go about storing a string in the Element struct (I can't make another member that is a string it has to be using the void pointer)

Can I use strcopy or sscanf ?

Sample main below in case I'm doing something wrong

#include "test.h"
int main (void)
{  
    Element* array = malloc(3 * sizeof(Element));
    ((*int)(array[0].data)) = 65;
    ((*int)(array[1].data)) = 64;
    ((*int)(array[2].data)) = 66;
}

EDIT

Sorry I should have added that the data will be added using a loop (the iterations is based on user input, so arrayOfElements could have 5,8,20 ect elements), based on user3386109 answer

Element* arrayOfElements = malloc(3 * sizeof(Element));
arrayOfElements[0].data = malloc( sizeof(int) );
int *ptr = arrayOfElements[0].data;
*ptr = 65;

work perfectly but if I want to make arrayOfElements[1].data = 67

Element* arrayOfElements = malloc(3 * sizeof(Element));
 arrayOfElements[1].data = malloc( sizeof(int) );
 int *ptr = arrayOfElements[1].data;
 *ptr = 76;

I can't reuse *ptr even if I do free(ptr) , is there anyway to do this if you don't know how many elements arrayOfElements will have?

Upvotes: 2

Views: 2051

Answers (2)

user3386109
user3386109

Reputation: 34829

The malloc in your question creates an array of three structs. Each struct has an uninitialized pointer called data. Before you use that pointer you must initialize it with another call to malloc.

To store an int:

array[0].data = malloc( sizeof(int) );
int *ptr = array[0].data;
*ptr = 65;

To store a string:

array[0].data = malloc( strlen(str) + 1 );
strcpy( array[0].data, str );

Here's a complete example that shows how to initialize the array, print the elements of the array, and then free the array. Note that ptr is just a temporary variable that's used to avoid the nasty syntax associated with casting and dereferencing a void *. (A good compiler will optimize out the ptr variable.)

int main( void )
{
    int *ptr;
    char *str = "hello";

    Element *array = malloc(3 * sizeof(Element) );

    array[0].data = malloc( sizeof(int) );
    ptr = array[0].data;
    *ptr = 65;

    array[1].data = malloc( strlen(str) +  1 );
    strcpy( array[1].data, str );

    array[2].data = malloc( sizeof(int) );
    ptr = array[2].data;
    *ptr = 76;

    ptr = array[0].data;
    printf( "%d\n", *ptr );
    str = array[1].data;
    printf( "%s\n", str );
    ptr = array[2].data;
    printf( "%d\n", *ptr );

    for ( int i = 0; i < 3; i++ )
        free( array[i].data );
    free( array );
}

Upvotes: 4

Serge Ballesta
Serge Ballesta

Reputation: 148870

You are in a corner case here. C standard (draft n1256) specifies in 6.3 Conversions:

2 Conversion of an operand value to a compatible type causes no change to the value or the representation

And later in 6.3.2.3 Pointers:

5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.56)

6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

The standard library defines even a special integer type intptr_t that can accept without loss any pointer, but this is only an informative part.

Anyway, in all common implementations, it is safe to cast an integer to a pointer back and forth provided :

  • if it was originally an integer, you never try to reference it, but convert it back to an integer (same type as original) before using it. As the cast shall not have changed the representation you get back the original value
  • if it was originally a pointer, you do not try to use it as an integer, unless your implementation ensures that there are no trap representation - common implementations allows it
  • the integer type accepts all pointer representations - if unsure use intptr_t

So you can do:

array[0].data = (void *) (intptr_t) 65;

and later

int i = (intptr_t) array[0].data;

Upvotes: 1

Related Questions