na1368
na1368

Reputation: 127

User defined types with dynamic size in C

I want to define a new data type consisting of an array with a size inputted by the user. For example if the user inputs 128, then my program should make a new type which is basically an array of 16 bytes. This structure's definition needs to be global since I am going to use that type thereafter in my program. It is necessary to have a dynamic size for this structure because I will have a HUGE database populated by that type of variables in the end.

The code I have right now is:

struct user_defined_integer;
.
.
.
void def_type(int num_bits)
{
    extern struct user_defined_integer 
    {
             int val[num_bits/sizeof(int)];
    };

return;

}

(which is not working)

The closest thing to my question, I have found, is in here: I need to make a global array in C with a size inputted by the user (Which is not helpful)

Is there a way to do this, so that my structure is recognized in the whole file?

Upvotes: 5

Views: 1717

Answers (4)

I want to define a new data type consisting of an array with a size inputted by the user. For example if the user inputs 128, then my program should make a new type which is basically an array of 16 bytes.

This is not possible in C, because C types are a compile-time thing and don't exist at all at run-time.

However, with a C99 conforming compiler, you might use flexible array member. You'll need a struct containing some members and ending with an array without any given dimension, e.g.

struct my_flex_st {
   unsigned size;
   int arr[]; // of size elements
};

Here is a way to allocate it:

struct my_flex_st *make_flex(unsigned siz) {
  struct my_flex_st* ptr 
    = malloc(sizeof(struct my_flex_st) + siz * sizeof(int));
  if (!ptr) { perror("malloc my_flex_st"); exit(EXIT_FAILURE); };
  ptr->size = siz;
  memset (ptr->arr, 0, siz*sizeof(int));
  return ptr;
}

Don't forget to free it once you don't use it anymore.

Of course, you'll need to use pointers in your code. If you really want to have a global variable, declare it as e.g.

extern struct my_flex_st* my_glob_ptr;

Upvotes: 2

Quentin
Quentin

Reputation: 63144

What you need is a VLA member, as asked about here. Basically, you declare a struct with a size field and one element's worth of storage as last member, and over-allocate it.

Imported from that question :

typedef struct Bitmapset {
    int nwords;
    uint32 words[1];
} Bitmapset;

Bitmapset *allocate(int n) {
    Bitmapset *p = malloc(offsetof(Bitmapset, words) + n * sizeof *p->words);
    p->nwords = n;
    return p;
}

Upvotes: 2

Sathish
Sathish

Reputation: 3870

Try this method-

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
struct user_defined_integer
{
        int *val;
}user_int;
void memory_allocate(int num_bit)
{
        int result;
        result = (num_bit+CHAR_BIT-1)/CHAR_BIT; // since 8 bit =1 byte
        user_int.val=malloc(result*sizeof(int));
        if(user_int.val == NULL){
        printf("Failed to allocate memory\n");
        return ;
        }
        else
        printf("Allocated %d bytes for val\n",result);
}
int main()
{
        int num_bit;
        printf("Enter the number of bits\n");
        scanf("%d",&num_bit);
        memory_allocate(num_bit);
        // do your stuff here

        free(user_int.val); // free the memory at the end;
        return 0;
}

Upvotes: 1

user3977796
user3977796

Reputation: 76

When doing:

extern struct user_defined_integer 
{
         int val[num_bits/sizeof(int)];
};

You should get the warning:

warning: useless storage class specifier in empty declaration 

because you have an empty declaration. extern does not apply to user_defined_integer, but rather the variable that comes after it. Secondly, this won't work anyway because a struct that contains a variable length array can't have any linkage.

error: object with variably modified type must have no linkage

Even so, variable length arrays allocate storage at the point of declaration. You should instead opt for dynamic memory.

#include <stdlib.h>

typedef struct
{
    int num_bits;
    int* val;
} user_defined_integer;

void set_val(user_defined_integer* udi, int num_bits)
{
    udi->num_bits = num_bits;
    udi->val = malloc(num_bits/sizeof(int));
}

Upvotes: 6

Related Questions