I have a **void where each position point to *void that point to my struct record with 3 fields (*char, int, float). I want to load data from a csv in my struct, but when it's time to reallocate memory, because size is equal to array's capacity, I got realloc(): invalid next size. I did not get my printf("realloc fails") so I think that tmp is not null, but anyway I lost my memory pointer.
struct record{
int id;
char* field1;
int field2;
float field3;
};
long array_size = 0;
long array_capacity = INITIAL_CAPACITY;
void** array;
void** array_create(){
void **array = (void**)malloc(INITIAL_CAPACITY*sizeof(void*));
if(array == NULL){
fprintf(stderr, "array_create: unable to allocate memory for the array");
exit(EXIT_FAILURE);
}
return array;
}
void add_on_array(void** array, void* elem){
if(array == NULL){
fprintf(stderr,"add_on_array: array parameter cannot be NULL");
exit(EXIT_FAILURE);
}
if(elem == NULL){
fprintf(stderr,"add_on_array: elem parameter cannot be NULL");
exit(EXIT_FAILURE);
}
if(array_size >= array_capacity){
void** tmp = realloc(array, 2*(sizeof(void*)*array_capacity));
if(tmp == NULL){
printf("Realloc fails\n");
exit(EXIT_FAILURE);
}
array = tmp;
array_capacity = 2*array_capacity;
}
array[array_size] = elem;
array_size++;
}
while(fgets(buffer,buf_size,fp) != NULL){
read_line_p = strdup(buffer);
if(read_line_p == NULL){
fprintf(stderr,"main: unable to allocate memory for the read line");
exit(EXIT_FAILURE);
}
// strcpy(read_line_p,buffer);
char *id_field_in_read_line_p = strtok(read_line_p, ",");
char *field1_in_read_line_p = strtok(NULL,",");
char *field2_in_read_line_p = strtok(NULL,",");
char *field3_in_read_line_p = strtok(NULL, ",");
char *field1 = malloc((strlen(field1_in_read_line_p)+1)*sizeof(char));
if(field1 == NULL){
fprintf(stderr,"main: unable to allocate memory for the string field of the read record");
exit(EXIT_FAILURE);
}
int id = atoi(id_field_in_read_line_p);
strcpy(field1,field1_in_read_line_p);
int field2 = atoi(field2_in_read_line_p);
float field3 = atof(field3_in_read_line_p);
struct record *record_p = malloc(sizeof(struct record));
if(field1 == NULL){
fprintf(stderr,"main: unable to allocate memory for the read record");
exit(EXIT_FAILURE);
}
record_p->id = id;
record_p->field1 = field1;
record_p->field2 = field2;
record_p->field3 = field3;
add_on_array(array, (void*)record_p);
free(read_line_p);
}
fclose(fp);
stampa_array(array, array->size);
printf("\nData loaded\n");
}
Well, you are doing some "real bad" things here.
First of all you have a global variable with the name array here:
void** array;
In general global variables is something you should avoid. (In the rare cases where you really need a global variable, I'll recommend that you give it an "ugly" name that isn't used for anything else - like: globalVariableArray)
But worse - you also have a function that has an argument named array here:
void add_on_array(void** array, void* elem){
...
}
What does that mean? Having both a global array and an argument array? Which will be accessed in the function?
The answer is that the function argument array acts as a function local variable and it will hide the global variable.
So when you do:
array = tmp;
you change the local array variable - not the global.
When the function return the local variable no longer exists, i.e. any changes made to it is lost.
In other words - the memory allocated by realloc is lost and you have a leak.
First steps to fix this is:
Move the global variable into main
When calling a function that needs to change array, you need to pass the address of array, i.e. &array. Functioon prototype must be changed accordingly.
Likewise for the other globals...
But why not put all the array stuff into a struct?
Like:
struct ArrayContainer
{
long array_size;
long array_capacity;
void** array;
}
And in main do:
struct ArrayContainer container = {0, INITIAL_CAPACITY, NULL};
container.array = ...; // Allocate INITIAL_CAPACITY
I think that will simplify your code a lot as you only need to pass a pointer to this struct to the functions. Then you can change all three members through that pointer.
Related
This is just part of a bigger code, but it's full of errors so I try to fix them one by one. When I try to use malloc on my pointer vector the line returns this error
main.c|14|error: expected '{' before '*' token
Any resolutions?
struct students {
int group;
char name[20];
int grade;
};
int main()
{
struct students *ptr[100];
int num, i, max=0;
scanf("%d", &num);
ptr = (struct*) malloc(num * sizeof(struct));
if(ptr == NULL)
{
printf("error");
exit(0);
}
}
Struct is reserved keyword for declaring/defining structures in C, it isn't variable, nor something you cant get size of it. You have declared struct students (according to your code, i think it should be student instead of students), now you have to define a variable and allocate space for 100 structs via a double pointer, the code should be something like this
struct student {
int group;
char name[20];
int grade;
};
int main()
{
struct student ** ptr;
int num, i, max=0;
scanf("%d", &num);
ptr = malloc(num * sizeof(struct student));
if(ptr == NULL)
{
printf("error");
exit(0);
}
}
Now you can access individual students with array subscript
ptr[0]->grade = 20; // putting 20 in grade of first student
Also, there is no need for casting malloc result in C
While using malloc for a 1D array, you should allocate a pointer, not an array of pointers as you have done.
While allocating you are using sizeof(struct). The type here is struct students and you need sizeof(struct students)
Do not cast the result of malloc. See Do I cast the result of malloc?
The final code is
struct students *ptr;
ptr = malloc (num * sizeof(struct students));
You have an array of pointers to structure. You should allocate memory for them separately.
for(int i=0; i<100 && i<num; i++)
{
ptr[i] = malloc(sizeof(struct students));
if(0 == ptr[i])
{
/* Handle this case. */
}
}
/* Your code. */
/* At the end free the memory. */
for(int i=0; i<100; i++)
{
if(0 != ptr[i])
{
free(ptr[i]);
ptr[i] = 0;
}
}
But I think you just wanted to allocate an array of struct students. In that case you just need one pointer.
struct students *ptr = 0;
/* You allocate memory and store it in that pointer. */
ptr = malloc(num * sizeof(struct students));
if(0 == ptr)
{
/* Handle this case. */
}
You can access ith element of the array like ptr[i]. But add necessary checks and make sure i < num.
You need to free the allocated memory whenever you are done using the array.
if(0 != ptr)
{
free(ptr);
ptr = 0;
}
I've looked enough about this problem on this site and still haven't found a solution.
I have an array of struct, and I want to read from a file some records and store them in the structs. The problem is the allocation of the memory.
This is the struct I use:
struct Rec{
int mat;
char *nome;
char *cognome;
};
typedef struct Rec* Record;
This is the readFromFile function:
void readFromFile(char* fileName, Record** data, int* pn)
{
char line[LINE_LENGTH];
int n, i;
char* token;
printf("\n\nReading file %s\n", fileName);
FILE* fin = fopen(fileName, "r");
if (fin == NULL)
{ printf("Error readinf file\n");getch();
goto end;
}
n = 0; // first read to know the number of lines
while (fgets(line, LINE_LENGTH, fin) != NULL) n++;
n = (n < MAX_LENGTH ? n : MAX_LENGTH);
printf("N: %d\n", n);
*pn = n;
//Then I allocate the memory for the n lines I previously read
*data = (Record*)malloc(n * sizeof(Record));
if(*data == NULL){
printf("Problem allocating memory\n");
exit(0);
}
i = 0;
for(i = 0; i < n; i++){
(*data)[i].nome = malloc(sizeof(char) * MAX_LENGTH + 1);
if((*data)[i]->nome == NULL){
printf("Problem allocating memory\n");
exit(1);
}
//Here comes the problem, the allocation of the second string fails and the program exit
(*data)[i]->cognome = malloc((sizeof(char) * MAX_LENGTH + 1));
if((*data)[i]->cognome == NULL){
printf("Problem allocating memory\n");
exit(2);
}
}
rewind(fin);
n = 0;
while (fgets(line, LINE_LENGTH, fin) != NULL && n < MAX_LENGTH)
{
token = strtok(line, ";");
strcpy((*data)[n]->nome, token);
token = strtok(line, ";");
strcpy((*data)[n]->cognome, token);
token = strtok(line, ";");
(*data)[n]->mat = atoi(token);
n++;
}
fclose(fin);
end:return;
}
I've tried to modify the structure and the code in many ways but have not found a solution, I think that probably is a pointer problem but I can't figure it out. The readFromFile function was provided from the professor and was built to read int from file and I had to modify it to read records.
There's a big difference between:
(*data)[i].nome = malloc(sizeof(char) * MAX_LENGTH + 1);
and:
(*data)[i]->cognome = malloc((sizeof(char) * MAX_LENGTH + 1));
The first line with the dot notation used, is implying, access to a member of a struct, whereas the -> implies accessing a member of a struct using pointer notation, i.e. pointer to a structure.
The confusion is showing there, as (*data) is a pointer to a struct of type Record which is a type definition of Rec.
typedef struct Rec* Record;
Since data when stripped down, is type definition of Record, aliased to a pointer to struct of Rec. The double pointer as part of parameter, which will be modified through pass by reference, is declared, after determining the number of lines in input dataset, as an array of pointers:
*data = (Record*)malloc(n * sizeof(Record));
Accessing the member data, for each entry in the array would be:
(*data)[i] dot name_of_member
The rule would have changed, had the type definition be like this:
typedef struct Rec Record;
i.e. a normal struct, no pointer usage.
Then access to the member data would have been, if allocation was achieved,
(*data)[i]->name_of_member
However, do not try hide pointers behind a typedef as that will give grief, come back to the code again in the future, and wondering why it failed, the hidden pointer has bitten you!
Record is defined as
typedef struct Rec* Record;
therefore it is pointer to struct Rec. malloc returns pointer to allocated memory (or NULL) but you cast this to pointer to pointer
*data = (Record*)malloc(n * sizeof(Record));
// = Rec**
I want to create function that adds words into dictionary
so far i made this
void addWord(char **dictionary,int *dictionarySize,int *wordsInDictionary,char *word){
if(dictionary == NULL)
{
*dictionary = (char *)malloc(sizeof(char*)*(*dictionarySize));
}
else
{
if(*wordsInDictionary==*dictionarySize)
{
*dictionary = (char *)realloc(dictionary,sizeof(char*)*(*dictionarySize)*2);
(*dictionarySize)*=2;
}
}
dictionary[*wordsInDictionary]=word;
(*wordsInDictionary)++;
}
in main() i have
int i;
int dictSize = 1;
int wordsInDict = 0;
char *word;
char *dictionary;
dictionary=NULL;
then i want to print all words in dictionary , but here i get warning that %s is expecting char* but it is int
printf("Stats: dictsize: %d, words in dict: %d\n", dictSize,wordsInDict);
for(i=0;i<wordsInDict;i++)
{
printf("%d. %s\n",i, dictionary[i]);
}
it also gives me errors when i try to add words
i use this call to add words
addWord(&dictionary,&dictSize,&wordsInDict,word);
In your addWord function, dictionary will never be NULL.
And that's only the start of your problems. Because you want dictionary to be an array of arrays, which mean you need to declare it as a pointer to a pointer (if you want it to be dynamic). However, you declare it as just a (single) pointer. It's in the main function (or where ever you declare it originally) that you need to declare it as a pointer to a pointer. And you need to initialize it, or it will have an indeterminate value and using it in any way other than initializing it will lead to undefined behavior.
That means your addWord function should take a pointer to a pointer to a pointer, i.e. one more level of indirection. And you need to use the dereference operator to get the original pointer to pointer.
So the addWord function should start like e.g.
void addWord(char ***dictionary, int *dictionarySize, int *wordsInDictionary,char *word){
if(*dictionary == NULL)
{
*dictionary = malloc(sizeof(char*) * (*dictionarySize));
}
...
}
Also note that I don't cast the return of malloc.
Also note that realloc can fail, and then will return NULL, so if you assign the return to the same pointer you reallocate you will loose the original pointer. Always use a temporary pointer for the return-value of realloc and only assign to the real pointer after checking that the reallocation succeeded.
I suggest that you put together the members of the dictionary in one as a structure, rather than having individually.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dictionary {
char **words;//array of char *
int size;
int numOfWords;
} Dictionary;
Dictionary *D_new(void){
Dictionary *dic = malloc(sizeof(*dic));
if(dic){
dic->size = 16;//initial size
dic->words = malloc(dic->size * sizeof(*dic->words));//check omitted
dic->numOfWords = 0;
}
return dic;
}
void D_drop(Dictionary *dic){
int i;
for(i=0;i<dic->numOfWords; ++i)
free(dic->words[i]);
free(dic->words);
free(dic);
}
void addWord(Dictionary *dic, const char *word){
if(dic == NULL){
return ;
}
if(dic->numOfWords == dic->size){
dic->words = realloc(dic->words, sizeof(*dic->words)*(dic->size*=2));//check omitted
}
dic->words[dic->numOfWords++]=strdup(word);//make copy
}
int main(void){
int i;
Dictionary *dictionary = D_new();
addWord(dictionary, "apple");
addWord(dictionary, "banana");
addWord(dictionary, "melon");
printf("Stats: dictsize: %d, words in dict: %d\n",
dictionary->size, dictionary->numOfWords);
for(i=0;i<dictionary->numOfWords;i++){
printf("%d. %s\n", i, dictionary->words[i]);
}
D_drop(dictionary);
return 0;
}
I want to create a new intarr_t with initial size len, but I've never handled this type of problem with a typedef'ed variable.
My problem is that intarr_create() should allocate the array space and then return a pointer to it if malloc was successful or a pointer to NULL if I failed. How can I fix this?
Also, why there is a * symbol in the function?
Here's my code:
#include <stdio.h>
typedef struct {
int* data;
unsigned int len;
} intarr_t;
intarr_t* intarr_create(unsigned int len) {
//intarr_t with initial size len
intarr_t = (int *) malloc(len); // not working here, can someone explain why?
if(intarr_t != NULL) {
return intarr_t;
} else {
return NULL;
}
}
int main() {
int len = 15;
int h = intarr_create(len);
printf("%d\n", h);
return 0;
}
It's not working because you did not give your variable a name. Also, int* and intarr_t are not the same type, so you will get a type mismatch unless you change the cast.
Rewrite your function into this:
intarr_t* intarr_create(unsigned int len)
{
intarr_t *result;
result = (intarr_t *)malloc(sizeof(intarr_t)); // allocate memory for struct
if(result != NULL)
{
result->data = (int *)malloc(len * sizeof(int)); // allocate memory for data
result->len = len;
if (result->data == NULL)
{
/* handle error */
}
}
else
{
/* handle error */
}
return (result);
}
You have to do a "double" malloc to get it right. First you have to allocate the memory for the intarr_t and if that was successful you have to allocate the memory for the data array.
Additionally malloc returns a void * which must be cast to the correct pointer type (should be a warning or maybe even an error with some compilers).
You have a few problems with your intarr_create function. First of all, you need to name your intarr_t variable. Now you have the slightly trickier problem of allocating memory for the actual array of integers in addition to your intarr structure. Remember, that you will have to call delete twice to destroy this object. Once on the data, and once on the actual structure itself.
intarr_t* intarr_create(unsigned int len)
{
intarr_t* array = (intarr_t*)malloc(sizeof(intarr_t));
array->data = (int*)malloc(len * sizeof(int));
return array;
}
I'm trying to store a string in an array contained within a struct, and access it, but I'm having a hard time. The struct looks like this:
typedef struct {
void **storage;
int numStorage;
} Box;
Box is initialized as such:
b->numStorage = 1000000; // Or set more intelligently
Box *b = malloc(sizeof(Box));
// Create an array of pointers
b->storage = calloc(b->numStorage,sizeof(void *));
In order to set the string, I use this function:
void SetString(Box *b, int offset, const char * key)
{
// This may seem redundant but is necessary
// I know I could do strcpy, but made the following alternate
// this isn't the issue
char * keyValue = malloc(strlen(key) + 1);
memcpy(keyValue, key, strlen(key) + 1);
// Assign keyValue to the offset pointer
b->storage[offset*sizeof(void *)] = &keyValue;
// Check if it works
char ** ptr = b->storage[offset*sizeof(void *)];
// It does
printf("Hashcode %d, data contained %s\n", offset, *ptr);
}
The problem lies when I try to retrieve it again, with the exact same offset:
// Return pointer to string
void *GetString(const Box *b, int offset, const char *key)
char ** ptr = b->storage[offset*sizeof(void *)];
if (ptr != NULL) {
printf("Data should be %s\n", *ptr);
return *ptr;
} else {
return NULL;
}
The returned pointer is gibberish. What could be amiss?
You don't have to specify the actual memory offset when accessing arrays. Simply give it the index and you will get the correct element.
So, in your third code block:
b->storage[offset] = keyValue;
And in your fourth:
char *ptr = b->storage[offset];
if (ptr != NULL) {
printf("Data should be %s\n", ptr);
return ptr;
} else {
return NULL;
}
Also, in the second block of code, has b->numStorage already been set?
b->storage[offset*sizeof(void *)] = &keyValue;
This stores the address of the local variable keyValue in the array. Once the function completes, this address becomes invalid. I think you want:
b->storage[offset*sizeof(void *)] = keyValue;
and then make the corresponding change while retrieving.
Doesn't this:
b->storage[offset*sizeof(void *)] = &keyValue
set storage[offset*sizeof(void*)] to point to the address of the local variable keyValue? i.e. no longer valid after function returns