Immanuel Immanuel -4 years ago 101
C Question

Resetting/Clearing a global array of pointers to structs

I'm new to C and I'm having a bit of a problem resetting or clearing a global array of pointers to structs.
I need to receive a file (or more) and read it's lines in two cycles.
while reading it I need to create a table of symbols(labels basically), and then use it to create more data (exporting the location of the labels to files writing it in hexadecimal values).

The problem I am having is when I'm reading two files. The first file is read fine and all the values are correct, but when it tries to read the second file the values in the table(array) I created are still there even though I free'd them.

I have this declared in a header file: (SIZE being 30)

typedef struct symbol{
unsigned action :1;
unsigned external :1;
int address;
char label[SIZE];
unsigned data_flag :1;
} symbol ;

symbol *symbol_Table[SIZE] ;


An example of adding a new symbol: (this sits in the reading function)

new_symbol = malloc(sizeof(symbol));
strcpy(new_symbol->label, temp);
new_symbol->external = 0;
new_symbol->address = DC - tok_count;
new_symbol->action = 0;
new_symbol->data_flag = 1;
add_symbol(new_symbol);
free(new_symbol);


The adding function, in a different file: (UPDATE)

if(count == SIZE){
**/*realloc the array size, increase it*/**
}

if(count < SIZE){
symbol_Table[count] = malloc(sizeof(symbol));
symbol_Table[count]->action = new_symbol->action;
symbol_Table[count]->external = new_symbol->external;
symbol_Table[count]->address = new_symbol->address;
strcpy(symbol_Table[count]->label, new_symbol->label);
symbol_Table[count]->data_flag = new_symbol->data_flag;

/*printf("count: %d\n", count);*/
return ++count;
}

return count;


And the freeing of the symbols at the end of the reading loop: (UPDATE)

int i;
for(i = 0; i < count ; i++){
free(symbol_Table[i]);
symbol_Table[i] = NULL;
}


this is the correct output after the first loop on the first file:

action: no | extern: yes | address: 0 | label L3 | data: no
action: no | extern: yes | address: 0 | label W | data: no
action: yes | extern: no | address: 100 | label MAIN | data: no
action: yes | extern: no | address: 106 | label LOOP | data: no
action: yes | extern: no | address: 119 | label END | data: no
action: no | extern: no | address: 0 | label STR | data: yes
action: no | extern: no | address: 7 | label LENGTH | data: yes
action: no | extern: no | address: 10 | label K | data: yes


and the faulty output after the first loop of the second file: (UPDATE)

action: yes | extern: no | address: 100 | label MAIN | data: yes
action: no | extern: yes | address: 0 | label W | data: yes
action: yes | extern: no | address: 108 | label LOOP | data: yes
action: no | extern: no | address: 0 | label STR | data: yes
action: no | extern: no | address: 3 | label K | data: yes


should be:

action: yes | extern: no | address: 100 | label MAIN | data: no
action: no | extern: yes | address: 0 | label W | data: no
action: yes | extern: no | address: 108 | label LOOP | data: no
action: no | extern: no | address: 0 | label STR | data: yes
action: no | extern: no | address: 3 | label K | data: yes


A few questions:


  1. Is there a way to clean the list after I used it? and then reusing the same list for new values? and avoiding the memory leak.

  2. Is this idea with arrays just a waste of space, should I try using linked lists instead? I fear that I will have to write my whole project again, and time is not on my side..



(AFTER UPDATE)


  1. How can I Reallocate more memory to increase the size of the array when I reach its end?



Apologies if I misused a term, I'm studying C in a different language.

Answer Source

Even though you are freeing your structs, your data is not immediately overwritten since the heap allocator isn't required to; it just makes a note that the space you freed is available. You should go one step further, and set each index of your array to NULL after freeing them. That will actually remove them from your array.

Now, I would be cautious when using an array. You have specified a size, but you aren't enforcing it in your add function.

If you swap your array over to use dynamic memory by using malloc, and you reach the size constraint later in the program, you can allocate more space using realloc (which would basically allow you to implement an ArrayList without disturbing the rest of your program's implementation).

To initially allocate space for your array, try:

symbol **symbol_Table = (symbol *) malloc(sizeof(symbol *) * SIZE);

Note: malloc can only be called from inside a method. So, at the top of your file, you can declare your variable:

symbol **symbol_Table;

Then, before using it, you should define it in your main() method:

symbol_Table = (symbol **) malloc(sizeof(symbol **) * SIZE);

Note the notation in the malloc statement - you need to multiply the size of the array with the size of a symbol pointer, because malloc takes the number of bytes that are to be allocated. sizeof(symbol *) gives you the size of a single symbol pointer.

Also: in order to use realloc, the initial allocation of symbol_Table should be something returned by malloc / calloc / realloc, or NULL.

If you're just trying to pop the reallocation into your if-statement, try:

static size_t current_size = SIZE;

if(count == current_size) {
  current_size = current_size << 1;
  symbol_Table = (symbol *)realloc(symbol_table, sizeof(symbol *) * current_size);
}

if(count < current_size) {
  // ... the rest of the code continues here

The bit about current_size << 1 is a bitshift left - it effectively multiplies current_size by two.

Static variables retain their values between function calls. So, if I change it when I call the function one time, the next time I call the function, the variable will have the value I set in the previous call. The reason for the static variable is that the value of current_size should be saved between calls if you increase the size of your array, and that you have to store the size of the array somewhere. The best place to store it is in the one function where the real size of the array is important - the only place where it will be upscaled. A global variable would work just as well though.


To free the symbol table at the end:

int i;
for(i = 0; i < count ; i++){
  if(symbol_Table[i] != NULL) // Important - we cannot free NULL
  {
    free(symbol_Table[i]);
    symbol_Table[i] = NULL;
  }
}
count = 0; // Important - if we are deleting everything in the array, we
           // need to make sure we reset the count for our next delete
           // operation
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download