Program Crashes When Accessing array inside Struct - c

I'm trying to implement the first part of an autocomplete feature that takes in a string, calculates an index for a particular letter, and then allocates another struct pointer at that index. It also stores possible completions of words in a string array. For some reason, the program crashes when I try to access the string array field, and I can't figure out why. How can I fix this?
Thanks
struct table {
struct table *next[26];
char **complete;
int lastIndex;
int size;
};
static struct table Base={{NULL},NULL,0,0};
void insert(const char *string){
int index=string[0]-'a';
if(Base.next[index]==NULL){
Base.next[index]=(struct table*)malloc(sizeof(struct table));
*Base.next[index]=(struct table){{NULL},NULL,0,0};
}
struct table *pointer=Base.next[index];
if(pointer->lastIndex==pointer->size){ //expand complete array
pointer->complete[pointer->lastIndex] = strdup(string); //program crashes here
pointer->lastIndex=pointer->lastIndex+1;
}
}

The crash in this line
pointer->complete[pointer->lastIndex] = strdup(string);
is because pointer->complete is NULL. In other words, you forgot to allocate memory for complete.
How can I fix this?
You must allocate memory. It seems that you want a dynamic sized array of char pointers. So you'll need to use realloc so that you both extend the allocated memory and preserve previous values.
Something like:
char** tmp = realloc(pointer->complete, (pointer->lastIndex + 1) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
// Then you can do your normal code
pointer->complete[pointer->lastIndex] = strdup(string);
Notice: Though it's possible to use realloc every time you insert a string, it may perform rather bad.
So instead of reallocating memory for every new string, it may be better to reallocate a chunk of memory each time you call realloc. Like:
if (pointer->lastIndex == pointer->size)
{
// Need more memory
// - if it's the first time just start with 10 (or another number)
// - else double the size
pointer->size = (pointer->size != 0) ? 2 * pointer->size : 10;
char** tmp = realloc(pointer->complete, (pointer->size) * sizeof(char*));
if (tmp == NULL)
{
// Out of memory
exit(1);
}
pointer->complete = tmp;
}
Here I decided to double the allocated memory when doing realloc. You can of cause use ant approach you like instead, e.g. always add 10 more instead of doubling.
BTW: The name lastIndex seems poor as it's really a nextIndex variable.
A final word on data structure
Your data structur, i.e. struct table seems a bit strange to me. At base-level, you only use table. At the next level you don't use table but only the other variables.
Seems to me that you should split up the struct into two structs like:
struct StringTable {
char **complete;
int lastIndex;
int size;
};
struct table {
struct StringTable strings[26];
};
That would save you both memory and some of the dynamic memory allocation.

You are assuming that
const char * string
will contain only small case alphabets. Dictionaries also have apostrophes
add that case.

Related

C dynamically allocate struct array and its components

What is the correct approach to dynamically allocate a struct array and its components in C? I have managed to do something that works,but I am kind of sceptical if it is correct.
I have the following code:
This is my struct array that I need to dynamically allocate:
typedef struct
{
char *wrong;
char *right;
}Dictionary;
This is the function I call when I need to initialise my struct array:
Dictionary *init_Dictionary(int nr_elem)
{
Dictionary *dict;
dict = malloc(nr_elem*sizeof(Dictionary));
for(int i=0; i<nr_elem; i++)
{
char wrong[101],right[101];
scanf("%s%s",wrong,right);
dict[i].wrong = malloc(strlen(wrong)*sizeof(char));
dict[i].right = malloc(strlen(right)*sizeof(char));
strcpy(dict[i].wrong,wrong);
strcpy(dict[i].right,right);
}
return dict;
}
Then in my main function, I have this:
int nr_elem;
scanf("%d",&nr_elem);
Dictionary *dict;
dict = init_Dictionary(nr_elem);
Also,when I finish work with the struct, how do I free the used memory ?
EDIT Thank you all for the quick and indepth answers!
For each allocation you need to allocate one more location to allow for \0 (NULL terminator) at the end of the string.
dict[i].wrong = malloc(strlen(wrong)*sizeof(char) +1 );
dict[i].right = malloc(strlen(right)*sizeof(char) +1);
To free, you first need to free all the pointers right and wrong in the array and then free the main dict array. Optionally, you can NULL the pointers after free.
Dictionary* freeDict(Dictionary *dict, int nr_elem)
{
for (int i=0; i<nr_elem; i++)
{
free(dict->wrong);
free(dict->right);
dict->wrong = NULL;
dict->right = NULL;
}
free (dict);
dict = NULL;
return dict;
}
//To call.
dict = free(dict, nr_elem);
The program design isn't good, you should separate UI from algorithms. Instead of this, you should first take the user input, then store it in 2 strings and pass the strings as parameters to init_Dictionary.
As for the allocation, it is almost correct. But you forgot to allocate space for the null terminator, it should be:
dict[i].wrong = malloc(strlen(wrong)+1);
dict[i].right = malloc(strlen(right)+1);
Multiplying with sizeof(char) isn't meaningful, since the definition of sizeof(char) is always 1 on all systems.
In a production-quality application, you must always check the result of each malloc, then handle errors.
You free memory the same way as you allocated it, but in the opposite order since you need dict itself to be valid until you have deallocated its members:
for(int i=0; i<nr_elem; i++)
{
free(dict[i].wrong);
free(dict[i].right);
}
free(dict);
As a rule of thumb, each call to malloc must be matched with a call to free.
There's a bug in your implementation: strlen(s) does not count the terminating 0-character, so, despite one test may work successfully, this is actually an UB. strdup can do work for you; if you don't have it standard library, simply add 1 when allocating memory for string copies. Or even better: count string length once, then use this value to both allocate enough bytes and copy contents with memcpy.
Otherwise your algorithm is quite useful (provided an array of string pairs is really what you need, with no additional structure like search index or anything).
To deallocate it, add a destructor that performs element-wise deallocation and then frees the whole array:
void destroy(Dictionary *dict, size_t nr_elem) {
for(size_t i = 0; i < nr_elem; ++i) {
free(dict[i].wrong);
free(dict[i].right);
}
free(dict);
}

Releasing memory of structure fields in an array in C

I'm writing a function in C which adds a new product entry to an array of structs. The array is defined in the following structure:
struct product_array {
struct product *arr;
unsigned int count; //Initially set to NULL, counts the number of entries
};
The array is dynamically allocated, but each time a new entry is added it should be reallocated. Each element of an array consists of product structure:
struct product {
char *title;
char code[8]; // Should be truncated to 7 characters
};
This is what I wrote:
void add_product(struct product_array *pa, const char *title, const char *code)
{
pa->arr = realloc(pa->arr, sizeof(struct product) * (pa->count + 1));
if (pa->arr == NULL)
return NULL;
char *temp = malloc(strlen(title) + 1); // for title memory
//should be dynamically allocated separately
if (temp == NULL){
return NULL;
}
memmove(temp, title, (strlen(title) + 1));
title = temp;
pa->arr[pa->count].title = title;
int j = 0;
while (*code) {
pa->arr[pa->count].code[j] = (*code);
code++;
j++;
if (j == 7)
break;
}
pa->arr[pa->count].code[j] = '\0';
pa->count++;
}
It seems to work fine (though I'm not sure if I used realloc correctly). But now I'm supposed to release the memory. I did it by writing:
free(pa->arr);
It also seems to be okay. But now I'm supposed to release memory which was allocated for title. To do that I should change main.c.
int main()
{
struct product_array pa;
pa.count = 0;
pa.arr = NULL;
add_product(&pa, "Product 1", "1111");
add_product(&pa, "Product 2", "123320");
add_product(&pa, "Product 3", "565496845");
}
And here I'm lost.
free (pa.arr->title);
doesn't seem to work.
Would really appreciate your help.
Before freeing the pa->arr, you have to iterate over the array, freeing each structure's title separately, like this:
for (int i = 0; i < pa.count; ++i)
{
free(pa.arr[i].title);
}
free(pa.arr);
There are many problems there.
Be careful when using realloc: If you call realloc() and there is not enough room to enlarge the memory allocation pointed out it will copy everything to a new position, what may be slow. So, if the array is something that you expect to change it's size a lot, and you are not working in a platform that has tight memory size restrictions, you should do it in a different way. For example: allocate a space for 500 entries, and when it gets full, call a realloc to grow it to 1000 entries. This way you save some processing power (and memory bandwidth) by using more memory.
Also, make sure you understand how memory allocation works. A good reference is http://www-bcf.usc.edu/~dkempe/CS104/08-29.pdf
For example, if you call:
free(pa->arr);
Just the array will be freed, all the titles will be still allocated in memory, but you lost all the references to them. This is called memory leak (http://en.wikipedia.org/wiki/Memory_leak).
In your main() class, you allocated 3 different instances of 'title', when you go to free the memory, you need to free 3 different instances of 'title'. The simple answer is to just loop through pa->arr and free the title from each member.
One trick I used when writing 'C' is to create a function that deallocates the members of a struct. Then if you are allocating in an array like above, you just loop through the array calling the free_() function to free all the members of the struct.
void free_product(struct product *p) {
free (p->title);
/* If you dynamically allocate more fields in p, free them here */
}
void free_product_array(struct product_array *pa)
{
int i;
for (i = 0 ; i < pa->count; i++) {
free_product(&pa->arr[i]);
}
free (pa->arr);
}
Your case is a bit different that what I normally do. I usually free the pointer itself at the end of the function, but I wouldn't do that here because you allocated an entire array for your product entries at once.

how to create a dynamic array of structs in C

I want to send a struct of symbol from one function to other functions, and i want to create an array that every cell will point to a different values of the following struct:
typedef struct symbol_def
{
char* sym_name;
char* sym_type;
unsigned short sym_address;
char sym_is_ext;
}symbol;
I'm trying to run this code:
//function-1
void compile_input_file(char* input)
{
symbol* curr_symbol;
//Intalize curr_symbol struct
curr_symbol = (symbol*)malloc(sizeof(symbol));
//memset((void)curr_symbol, 0, sizeof(symbol));
parse_command(line, &parser, curr_symbol, &index);
}
//function-2
void parse_command(char* line, parse_params* parser, symbol* curr_symbol, int* index)
{
sym = symbol_table_create(curr_symbol, "directive", sym_label, '0', index);
}
//function-3
symbol* symbol_table_create(symbol* curr_symbol,char* s_type, char* label, char is_ext, int* index)
{
int temp = *index;
curr_symbol = (symbol*)realloc(curr_symbol,sizeof(symbol*)*(temp+1));
curr_symbol[temp].sym_type = s_type;
curr_symbol[temp].sym_name = label;
curr_symbol[temp].sym_address = 0;
curr_symbol[temp].sym_is_ext = is_ext;
temp++;
*index = temp;
return curr_symbol;
}
The problem is that the curr_symbol gets override all the time.
my purpose is to build a table of symbols, that in every iteration on the code i'll add another cell to the array
any ideas?
There is a problem, with the realloc It should be curr_symbol = (symbol*)realloc(curr_symbol,sizeof(symbol)*(temp+1)); You were actually allocating it sizeof pointer which is 4 Bytes.
A Piece of Advice Realloc is a costly operation you should use it only if necessary and not on every instance
you could malloc in function3 instead of function1. If you do so you dont even need to pass the pointer via function2.
or else put a check to see if realloc is really necessary or not. Eg:- Check if the pointer is allocated memory. if(ptr!=null){ //realloc } This can work as a checking case too.
Best of Luck. :)

Extending a Structure Array

Would this be the proper way to extend a structure array?
typedef struct { int x,y,z;} student_record;
int main(){
student_record data_record[30]; // create array of 30 student_records
num_of_new_records = 5;
data_record = realloc(data_record,(sizeof(data_record) + (sizeof(student_record)*num_of_new_records)));
// do I now have an array of 35 student_records???
No - you can't assign to an array. Your code won't even compile - did you try it?
If you want to realloc() you need to have used malloc() (or one of its relatives):
student_record *data_record = malloc(sizeof(student_record) * 30);
You probably shouldn't be assigning the return value of realloc() back to the original variable, either. If it fails for some reason, you'll lose the original pointer and leak that memory.
You should follow the pattern of calloc'ing the initial size and then using realloc when necessary. Safe practice for realloc'ing need to include assigning the initial value returned to a temporary variable and over-writing the first after verifying that there are no errors. Something like this:
student_record *data_record = malloc(sizeof(student_record) * 30);
student_record *tmp;
// need larger size
if ((tmp = realloc(data_record, new_size)) == NULL)
perror(); //possibly exit as well since you're out of memory
else
data_record = tmp;
You can only use realloc on objects that are on heap (dynamically allocated) thus you have to malloc first.
typedef struct { int x,y,z;} student_record;
int main()
{
student_record *data_record = malloc(sizeof(student_record)*30);
assert(data_rocord);
data_record = realloc(data_record, sizeof(student_record)*35);
assert(data_record);
free(data_record);
exit(EXIT_SUCCESS);
}

How to know exist element of structure?

i have a simple structure:
typedef struct {
int test;
} struct1_t;
typedef struct {
struct1_t** tests;
} struct2_t;
struct2_t *str
for(i=0;i<1000;i++) {
(str->tests)[i]=(test1_t *) malloc(sizeof(test1_t));
(str->tests)[i]->test = i;
}
How to know exist str->tests)[i] element on not ?
if (str->tests)[i] != NULL
call Segmentation failed :).
Simply put, you can't. There is no way to know the length of an array in C, you have to keep track of it manually as your array changes or grows.
C arrays are really just blocks of memory, so what you really
want to do as add a field to your structs that keeps track of how
much space has been allocated and make sure you initialize
everything to sane values. You also have to be careful when using
pointers of structs containing to pointers to pointers of structs,
since in your example you failed to properly allocate memory for
everything.
Try this:
typedef struct {
int test;
} test_t;
typedef struct {
test_t* tests; /* We only need a regular pointer here */
size_t numtests; /* This is so we know how many tests we allocated */
} mystruct_t;
/* .... Now skip to the actual usage: */
mystruct_t *str;
int i;
str = malloc(sizeof(mystruct_t)); /* Remember to allocate memory for
the container! */
str->numtests = 1000; /* Set our size inside the container and use it! */
/* Now to allocate an array of tests, we only need to allocate
a single chunk of memory whose size is the number of tests
multiplied by the size of each test: */
str->tests = malloc(sizeof(test_t)*str->numtests);
/* Now let's initialize each test: */
for (i=0; i<str->numtests; i++) { /* Notice we use str->numtests again! */
str->tests[i]->test = 1; /* Notice we don't need all the extra
parenthesese. This is due to the operator
precedence of [] and -> */
}
Now when you need to see if a test element exists, you can just see if the
index is within the size of the container:
if (i >= 0 && i < str->numtests) {
str->tests[i]->test = 2; /* This code only runs if the index would exist. */
}
But that means you have to take care to always initialize str->numtests to be
a sane value. For example, with no allocated tests:
mystruct_t *str = malloc(sizeof(mystruct_t));
/* Initialize the container to sane starting values! */
str->tests = NULL;
str->numtests = 0;
And that's how you know if something exists -- you keep track of it inside
the structures you define. That's because C code maps very directly to
assembly language, and C structs and arrays map very directly to bits and bytes
in computer memory, so if you want to maintain meta information like how
many elements are inside your array, you have to make room for that information
and store it yourself.
It is pretty fundamental that you can't do it this way in C. Your struct2_t would need an extra field such as int no_of_tests, which you would update.
In fact to do what your trying to do there, you also need 2 mallocs -
struct2_t str;
str.tests = malloc( 1000 * sizeof(int) );
str.no_of_tests = 1000;
for(i=0;i<1000;i++) {
str.tests[i] = malloc( sizeof(struct1_t) );
str.tests[1]->test = i;
}
There is nothing in the language to do this for you, you need to keep track yourself. A common solution is to make the last pointer in an arbitrary-size array of pointers be a NULL pointer, so you know to stop looping when you hit NULL.
If your compiler supports _msize you can find out the size that you allocated. For example:
if (i < _msize((str->tests)/sizeof(test1_t))
then i is valid and points to an element of the allocated array

Resources