Growing arrays. Refer to the elements by pointers, not indexes - c

Since the array address may change when memory is reallocated,
the main part of the program (in the body of the function main ()) should refer to the elements by
indexes, not pointers. Why?
Can you show an example of accessing items with pointers?
(Sorry for my English).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Nameval Nameval;
struct Nameval {
char *name;
int value;
};
struct NVtab {
int nval; /* current number of values */
int max; /* allocated number of values */
Nameval *nameval; /* array of name-value pairs */
};
enum {NVINIT = 1, NVGROW = 2};
/* addname: add new name and value to nvtab */
int addname(struct NVtab *nvtab, Nameval newname) {
Nameval *nvp;
if (nvtab->nameval == NULL) { /* first time */
nvtab->nameval = (Nameval *) malloc(NVINIT * sizeof(Nameval));
if (nvtab->nameval == NULL)
return -1;
nvtab->max = NVINIT;
nvtab->nval = 0;
} else if (nvtab->nval >= nvtab->max) { /* grow */
nvp = (Nameval *) realloc(nvtab->nameval,
(NVGROW*nvtab->max)*sizeof(Nameval));
if (nvp == NULL)
return -1;
nvtab->max *= NVGROW;
nvtab->nameval = nvp;
}
nvtab->nameval[nvtab->nval] = newname;
return nvtab->nval++;
}
int main(void) {
struct NVtab nvtab = {0, 0, NULL};
int curnum;
curnum = addname(&nvtab, (Nameval) {.name="Andy", .value=12});
printf("%d\n", curnum);
curnum = addname(&nvtab, (Nameval) {.name="Billy", .value=18});
printf("%d\n", curnum);
curnum = addname(&nvtab, (Nameval) {.name="Jack", .value=71});
printf("%d\n", curnum);
for (int i = 0; i < nvtab.nval; i++) {
printf("%s %d\n", nvtab.nameval[i].name,
nvtab.nameval[i].value);
}
}
For example, why can`t we show array like this:
for (int i = 0; i < nvtab.nval; i++)
printf("%s %d\n", nvtab.*(nameval+i).name, nvtab.*(nameval+i).value);

You are not supposed to assign a pointer calculated for a specific index to a variable with storage duration which could extend over an insert operation.
That pointer could become invalid, so the lesson behind that example is to always re-evaluate iterators on dynamic data structures.
E.g. what not to do:
auto *foo = &nvtab.nameval[i];
addname(&nvtab, (Nameval) {.name="Billy", .value=18});
printf("%s %d\n", foo->name, foo->value);
In the last line it can work or crash. Depending on whether realloc moved the allocation or resized in-place. Except that you can never know for sure until you execute it, as it isn't even fully deterministic.

This is not valid syntax:
nvtab. *(nameval+i).name
The member access operator . expects to be followed by the name of the member. What you want is:
(*(nvtab.nameval+i)).name

Related

Sorting structures from files

I recently got an assignment to sort members in a struct by last name and if they are the same to sort by first name. What i have so far only reads their name and age from the file but I am not properly grapsing how I would be able to sort it. So far I gathered the data from the file but im at a loss from there. I followed a code I saw but i didnt get a proper grasping of the process so i reverted back to step one.
struct Members{
int id;
char fname[50];
char lname[50];
int age;
}bio;
int main(){
int i=0;
FILE *fptr;
file = fopen("Members Bio.txt", "r");
while ( fscanf(file, "%d%s%s%d", &bio[i].id,bio[i].fname,bio[i].lname,&bio[i].age) != EOF)
{
printf("%d %s %s %d %d\n", bio[i].id,bio[i].fname, bio[i].lname, bio[i].age);
i++;
}
fclose(fptr);
}
Can anyone help me out on this one?
Code goes something like this for your case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Members{
int id;
char fname[50];
char lname[50];
int age;
};
typedef int (*compare_func)(void*, void*);
int struct_cmp(void* s1, void* s2)
{
int l_result = strcmp(((struct Members*) s1)->lname, \
((struct Members*) s2)->lname);
if (l_result < 0)
return 1;
else if (l_result > 0)
return 0;
else
return (strcmp(((struct Members*) s1)->fname, \
((struct Members*) s2)->fname) < 0 ? 1 : 0);
}
void sort(void* arr,long ele_size,long start,long end,compare_func compare)
{
// Generic Recursive Quick Sort Algorithm
if (start < end)
{
/* Partitioning index */
void* x = arr+end*ele_size;
long i = (start - 1);
void* tmp=malloc(ele_size);
for (long j = start; j <= end - 1; j++)
{
if ((*compare)(arr+j*ele_size,x))
{
i++;
// Swap is done by copying memory areas
memcpy(tmp,arr+i*ele_size,ele_size);
memcpy(arr+i*ele_size,arr+j*ele_size,ele_size);
memcpy(arr+j*ele_size,tmp,ele_size);
}
}
memcpy(tmp,arr+(i+1)*ele_size,ele_size);
memcpy(arr+(i+1)*ele_size,arr+end*ele_size,ele_size);
memcpy(arr+end*ele_size,tmp,ele_size);
i= (i + 1);
sort(arr,ele_size,start, i - 1,compare);
sort(arr,ele_size,i + 1, end,compare);
}
}
int main()
{
FILE* fp;
int bio_max = 3;
struct Members bio[bio_max]; // Define bio to be large enough.
/* Open FILE and setup bio matrix */
/* For testing */
bio[0].id = 0;
strcpy(bio[0].fname, "");
strcpy(bio[0].lname, "Apple");
bio[0].age = 0;
bio[1].id = 1;
strcpy(bio[1].fname, "");
strcpy(bio[1].lname, "Cat");
bio[1].age = 1;
bio[2].id = 2;
strcpy(bio[2].fname, "");
strcpy(bio[2].lname, "Bat");
bio[2].age = 2;
/* Sort the structure */
sort(bio, sizeof(struct Members), 0, bio_max - 1, struct_cmp);
/* Print the sorted structure */
for (int i = 0; i < bio_max; i++) {
printf("%d %s %s %d\n", bio[i].id, bio[i].fname, \
bio[i].lname, bio[i].age);
}
}
Output
0 Apple 0
2 Bat 2
1 Cat 1
If the strings are not sorting in the way you want, you can redefine the struct_cmp function. Code is self explanatory, the base logic in the code is pass an array and swap elements using memcpy functions. You cant use simple assignment operator if you want to be generic, so that is why the element size is explicitly passed.
Edit
The code was not handling the condition, if lname are same. I missed it thanks for #4386427 for pointing this out.
I think you should define bio to be an array. And google sort algorithms please. Also recommend you google how to use libc function qsort.

Calloc does not initialize entire memory block to zero

While playing with the implementation of a hashmap toy example (for fun) I've found a strange behaviour, calloc does not initialize the entire memory block I want to zero, as supposed to do. The following code should produce no output if the entire memory block is zeroed:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define DICT_INITIAL_CAPACITY 50
typedef struct dictionary_item {
char* ptr_key;
void* ptr_value;
} dict_item;
typedef struct dictionary {
dict_item* items;
uint16_t size, max_capacity;
} Dict;
Dict* dict_new() {
Dict *my_dict = calloc(1, sizeof *my_dict);
my_dict->items = calloc(DICT_INITIAL_CAPACITY, sizeof my_dict->items);
my_dict->size = 0;
my_dict->max_capacity = DICT_INITIAL_CAPACITY;
for (int j = 0; j < my_dict->max_capacity; j++) {
int key_null = 1;
int value_null = 1;
if ((my_dict->items + j)->ptr_key != NULL)
key_null = 0;
if ((my_dict->items + j)->ptr_value != NULL)
value_null = 0;
if ((my_dict->items + j)->ptr_key != NULL || (my_dict->items + j)->ptr_value != NULL)
printf("item %d, key_null %d, value_null %d\n", j, key_null, value_null);
}
return my_dict;
}
int main(int argc, char** argv) {
Dict* dict = dict_new();
}
However it produces the output:
item 25, key_null 1, value_null 0
The only non-zero item is always the one at DICT_INITIAL_CAPACITY / 2. I've tried also using memset to put all the block to zero and the result is the same. If I put the memory to zero explicitly using:
for (int j = 0; j < my_dict->max_capacity; j++){
(my_dict->items + j)->ptr_key = 0;
(my_dict->items + j)->ptr_value = 0;
}
Then I get the desired behavior. But I do not understand why it does not work using calloc. What am I doing wrong?
my_dict->items = calloc(DICT_INITIAL_CAPACITY, sizeof my_dict->items);
Should be
my_dict->items = calloc(DICT_INITIAL_CAPACITY, sizeof *my_dict->items);
Also note that, in general, calloc may not set pointers to null (although it does on all modern systems that I know of). It would be safer to explicitly initialize any pointers that are meant to be null.
Having said that, you seem to be storing a size variable to indicate the size of the dictionary, so you could avoid this problem entirely by not reading entries beyond the current size; and when you do increase size then initialize the entries you have just added.

realloc() on array of structs gives invalid next size

I have this function. As you can see, everything is being done in the function, I'm not allocating in the main and then passing anything to it (I'll only return the pointer to the array once the function is done). The function in itself (with a fixed size for the array) works, but the realloc fails.
struct database *parse() {
int i = 0;
int n = 1;
FILE *dbase = (fopen(PATH, "r"));
if (dbase == NULL) {
fprintf(stderr, ERRORE_APERTURA);
exit(EXIT_FAILURE);
}
struct database *database_array = calloc(20*n, sizeof(struct database));
if (database_array == NULL) {
fprintf(stderr, "Impossibile allocare memoria\n");
exit(EXIT_FAILURE);
}
while (feof(dbase) == 0) {
fscanf(dbase, "%[^:]:%[^:]:\n", database_array[i].user, database_array[i].password);
database_array[i].iswritten = 1;
i++;
if (i > 20*n) {
n++;
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
database_array = new_database_array;
}
}
database_array[++i].iswritten = 0;
fclose(dbase);
return database_array;
}
I tried reading other explanations, but I can't understand what's wrong here.
The array I allocated with calloc is initially 20. then, when it's filled, I want it to double in size, so I use n, which will be 2, by 20, so 40.
The frustrating thing is that I tried reallocating an array of struct with a simpler program, and doing THE SAME THING works without any problem:
#include <stdio.h>
#include <stdlib.h>
struct prova {
int a;
int b[10];
};
int main() {
struct prova* array_struct = calloc(10, sizeof(struct prova));
array_struct[0].a = 2;
struct prova* tmp = realloc(array_struct, sizeof(struct prova) * 20);
free(array_struct);
array_struct = tmp;
array_struct[1].b[1] = 3;
printf("a = %d", array_struct[0].a);
printf("b = %d\n", array_struct[1].b[1]);
return 0;
}
What am I not seeing? (Please nevermind the fact that I'm not checking if realloc returns NULL, I'll add that later)
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
free(database_array);
You can't both reallocate something and deallocate it. You can do either, but once you've done either, the previous allocation no longer exists, so you can't do the other.
After the first line of code above, the value of database_array should not be used anymore because it may not be valid.

Loss of values in array in struct after function execution

I am working on a c code that holds a structure that hosts some values which I call range.
My purpose is to use this so called range dynamically (holding different amount of data at every execution). I am now provisionally using the # define comp instead. This so called range gets updated every time I call my update_range though the use of s1 structure (and memory allocations).
What I found weird is that when I introduced a "show_range" function to output the actual values inside/outside the update function I realized that I loose the first two values.
Here is the code.
Any suggestions on that?
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <complex.h>
#define comp 1024
// struct holding a complex-valued range
struct range {
int dimensions; /* number of dimensions */
int* size; /* array holding number of points per dimension */
complex double* values; /* array holding complex valued */
int components; /* number of components that will change on any execution*/
};
// parameters to use in function
struct s1 {
int tag;
struct range* range;
};
int update_range(struct s1* arg);
int show_range(struct range* argrange, char* message);
int copy_range(struct range* in, struct range* out);
int main(void) {
int ret = 0;
struct s1 s1;
s1.tag = 0;
s1.range = malloc(sizeof(struct range));
update_range(&s1);
show_range(s1.range, "s1.range inside main function");
return ret;
}
////////////////////////////////////////////
int update_range(struct s1* arg) {
int ret = 0;
int i;
struct range range;
range.dimensions = 1;
range.size = malloc(range.dimensions * sizeof(int));
range.components = comp;
range.size[0] = range.components; // unidimensional case
range.values = malloc(range.components * sizeof(complex double));
for (i = 0; i < range.components; i++) {
range.values[i] = (i + 1) + I * (i + 1);
}
show_range(&range, "range inside update_range function");
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown
copy_range(&range, arg->range);
show_range(arg->range, "arg->range inside update_range function");
if (range.size)
free(range.size);
range.size = NULL;
if (range.values)
free(range.values);
range.values = NULL;
return ret;
}
////////////////////////////////////////////
// Show parameters (10 first values)
int show_range(struct range* argrange, char* message) {
int ret = 0;
vint i;
printf(" ******************************\n");
printf(" range in %s \n", message);
printf(" arg.dimensions=%d \n", argrange->dimensions);
printf(" arg.size[0]=%d \n", argrange->size[0]);
printf(" argrange.components=%d \n", argrange->components);
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
printf("\n");
return ret;
}
////////////////////////////////////////////
// copy range
int copy_range(struct range* in, struct range* out) {
int ret = 0;
if (in == NULL) {
fprintf(stderr, "error: in points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
if (out == NULL) {
fprintf(stderr, "error: out points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
out->dimensions = in->dimensions;
out->size = in->size;
out->values = in->values;
out->components = in->components;
cleanup:
return ret;
}
Your copy_range function is broken, because it copy only pointer to size and values and not the memory. After you call free(range.size); and free(range.values); you are deleting mamory also from original object but without setting its pointers back to NULL.
After calling update_range, s1.range has non NULL pointers in size and values, but they are pointing to deleted memory.
You are experiencing undefined behaviour (UB) due to accessing freed memory. Your copy_range() function only does a shallow copy of the two pointer fields so when you run free(range->size) you make arg->range->size invalid.
You should make copy_range() a deep copy by allocating and copying the pointer contents like:
out->size = malloc(in->dimensions * sizeof(int));
memcpy(out->size, in->size, in->dimensions * sizeof(int));
out->values = malloc(in->components * sizeof(complex double));
memcpy(out->values , in->values, in->components * sizeof(complex double));
There are not 10 items to print, so the lines:
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
Will be printing from random memory.
a much better method would be:
printf(" first %d {Re} values: \n", min(argrange.components,10));
for (i = 0; i < argrange.components; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
The above is just one of many problems with the code.
I would suggest executing the code using a debugger to get the full story.
as it is, the code has some massive memory leaks due mostly
to overlaying malloc'd memory pointers.
for instance as in the following:
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown

Insert function of Hashtable in C

So, I have the functions. How can I insert numbers in the Hashtable? A for that goes until the size of the table? I don't know what goes inside the for, if it is exists.
#include <stdio.h>
//Structure
typedef struct Element {
int key;
int value;
} Element;
typedef struct HashTable {
Element *table[11];
} HashTable;
//Create an empty Hash
HashTable* createHashTable() {
HashTable *Raking = malloc(sizeof(HashTable));
int i;
for (i = 0; i < 11; i++) {
Raking->table[i] = NULL;
}
return Raking;
}
//Insert element
void insertElement(HashTable *Raking, int key, int value) {
int h = hashFunction(key);
while(Raking->table[h] != NULL) {
if(Raking->table[h]->key == key) {
Raking->table[h]->value = value;
break;
}
h = (h + 1) % 11;
}
if(Raking->table[h] == NULL) {
Element *newElement = (Element*) malloc(sizeof(Element));
newElement->key = key;
newElement->value = value;
Raking->table[h] = newElement;
}
}
int main() {
HashTable * Ranking = createHashTable();
/** ??? **/
}
Could someone explain to me how to write my main function with these structures? In this case I'm fixing the number of elements in this table, right? (table [11]) What could I do for the user to determine the size of the hash table? is it possible? Or should I set the size?
I've added comments and changes to your code that I feel will be of use to you. I've also adapted it so that size is not hardcoded. Finally I free all the malloc-ed statements.
This compiles without errors and I've tested it for memory leaks and other errors using valgrind and found no complaints.
Let me know if something is not clear and the comments fail to explain it. I've tried to stick to your code as much as possible but I've not had a chance to test the functionality properly.
#include <stdio.h>
#include <stdlib.h>
//Structure
typedef struct Element {
int key;
int value;
} Element; /* you had a syntax error here */
typedef struct HashTable {
int size; /* we will need the size for the traversal */
Element *table; /* leave it as a pointer */
} HashTable; /* a syntax error here too */
HashTable* createHashTable(int size) {
HashTable *Ranking = malloc(sizeof(HashTable));
/* set the pointer to point to a dynamic array of size 'size' */
/* this way you don't have to hardcode the size */
Ranking->table = malloc(sizeof(Element) * size);
Ranking->size = size;
/* initialisation is a bit different because we don't have pointers here */
/* only table is a pointer, not its elements */
int i;
for (i = 0; i < size; i++) {
Ranking->table[i].key = 0;
Ranking->table[i].value = 0;
}
return Ranking;
}
/* I implemented a fake hashFunction just to test the code */
/* all it does is make sure the key does not exceed the size of the table */
int hashFunction(int key, int size)
{
return (key % size);
}
//Insert element
void insertElement(HashTable *Ranking, int key, int value) {
int h = hashFunction(key, Ranking->size);
int i = 0;
/* if hash is full and key doesn't exist your previous loop would have gone on forever, I've added a check */
/* also notice that I check if table[h] has empty key, not if it's null as this is not a pointer */
while(Ranking->table[h].key != 0 && (i < Ranking->size)) {
if(Ranking->table[h].key == key) {
Ranking->table[h].value = value;
return; /* break is intended to quit the loop, but actually we want to exit the function altogether */
}
h = (h + 1) % Ranking->size; /* changed 11 to the size specified */
i++; /* advance the loop index */
}
/* okay found a free slot, store it there */
if(Ranking->table[h].key == 0) {
/* we now do direct assignment, no need for pointers */
Ranking->table[h].key = key;
Ranking->table[h].value = value;
}
}
int main() {
int size = 0;
scanf(" %d", &size);
HashTable *Ranking = createHashTable(size);
insertElement(Ranking, 113, 10); /* this is just a test, 113 will be hashed to be less than size */
/* we free everything we have malloc'ed */
free(Ranking->table);
free(Ranking);
return 0;
}

Resources