user2035045
user2035045

Reputation: 27

Multiple arrays with malloc

I am initializing a struct called Array which consists of an array of Items and an int to keep track of the number of the Items.

  typedef struct anything{
    char text[MAXI];
    int any;
  }Item;

  typedef struct array{
    Item arr[0];
    int size;
  }Array;

To initialize the Array, I'm using malloc and returning the pointer.

Array create(){
    Array *p1 = malloc(sizeof(Array));
    p1->size = 0;
    return *p1;
}

The problem I have is that some functions are designed for 2 Arrays, such as intersection:

Array intersection(Array S,Array T){
    int i, j;
    Array I = create();
    for(i=0; i<(S.size); i++){
        for(j=0; j<(T.size); j++){
            if((compStructs(S.arr[i], T.arr[j])) == true)
                add(I, S.arr[i]);
        }
    }
    return I;
}

According to this code, if I were to execute create() twice, I would lose the pointer to the first array. Is there something I can do in the main program to prevent this, or what modifications can I do to the current function?

Edit: Added the add item function:

void add(Array S,Item x){

bool rep = false;
    int i = 0;
    for(i = 0; i<(S.size); i++){
        if(compStructs(x,S.arr[i]) == true)
            rep = true;
    }
    if(rep == false){
            Item *p2 = realloc(S.arr, sizeof(Item));
            *p2 = x;
            (S.size)++;
    }
    else
        printf("The item is already in the set.");

}

My main problem is that I'm not sure how to call two seperate arrays which are to be created at the user's request. The program is in it's build up but currently it looks somehitng like this:

#include "array.h"
Item x;

void arraymenu(){
    char inp;
    while((inp = getchar())!= '\n'){
        printf("a. To Create a new Array\n"
                "b. To Add a new Item\n"
                "c. To Remove an Item\n"
                "d. To Clear all contents of the Array\n"
                "e. To Get the size of the Array\n"
                "f. To Get a list of the number of elements of your choice\n"
                "g. To Check whether the array is empty\n"
                "h. To Get the union of two sets\n"
                "i. To Get the intersection of two sets\n"
                "j. To Get the difference of two sets\n"
                "k. To Check if a set is the subset of the other one\n"
                "l. To map a function to all Items of an Array\n"
                "m. To apply a function to all Items of an Array\n"
                "n. To store the Array in a File\n"
                "o. To load the Array from a File\n"   );

        switch(inp){
            case 'a' :  printf("Array A has been created.");
                        Array A = create();
                        break;

            case 'b' :  printf("Enter any integer, followed by any string.");
                        scanf("%d", &x.any);
                        scanf("%s", &x.text);
                        add(A, x);
                        break;

            case 'c' :  printf("Enter the integer and string you wish to remove ");
                        scanf("%d", &x.any);
                        scanf("%s", &x.text);
                        removee(A,x);
                        break;
        }
    }
}

Upvotes: 0

Views: 883

Answers (2)

Elias Van Ootegem
Elias Van Ootegem

Reputation: 76433

Basically, instead of a derefferenced pointer to a variable local to a given function's scope you need to return a pointer (BTW, compiling return *ptr should give a warning when compiling, add -Wall, and don't ignore what the compiler is telling you):

Array *create()
{
    Array *a_ptr = malloc(sizeof(*a_ptr));
    if (a_ptr == NULL) exit (EXIT_FAILURE);//failed to allocate memory
    a_ptr->size = 0;
    return a_ptr;
}

To be called like this:

Array *S, *T;
S = create();
T = create();

Now you have 2 arrays ready to play with. Note that you'll need to either dereference these pointers, or use the indirection operator on them always:

(*S).size = 1;
//or
S->size += 123;

You'll also probably want to change intersection to something like:

Array *intersection(Array *S,Array *T)
{
    int i, j;
    Array *I = create();
    for(i=0; i<(S->size); ++i)
    {
        for(j=0; j<(T->size); ++j)
            if(compStructs(S.arr[i], T.arr[j])) add(I, S.arr[i]);
        }
    }
    return I;
}

Of course, once you're done with all of these Array structs, you'll have to free() them, too.

As far as compStructs and add go, I expect you'll have to work on those functions, too. While you're at it, perhaps change the struct to better fit the way you're using it:

typedef struct array
{
    Item *arr;
    size_t size;//size_t makes more sense here
  }Array;

Of course, this in turn requires a bit more work when free-ing the memory, so a generic free function is advisable:

void free_array(Array **a)
{//pointer to pointer
    while((*a)->size--) free((*a)->arr+(*a)->size);
    free(*a);
    *a = NULL;//NULL pointers are safer
}
//call like so:
free_array(&Array_ptr);//yes, address of pointer

And realloc calls should look something like:

realloc(a->arr, (a->size + 1)*sizeof(*(a->arr)));
a->size += 1;

Upvotes: 1

BLUEPIXY
BLUEPIXY

Reputation: 40145

typedef struct array{
    int size;
    Item arr[];
}Array;

Array *create(int size){
    Array *p1 = malloc(sizeof(Array) + size*sizeof(Item));
    if(p1)p1->size = size;
    //return *p1;//memory leak
    return p1;
}

Upvotes: 1

Related Questions