I'm trying to solve a problem I'm having with a function that will create a new struct objects and then put it in an dynamic array. I have tried multiple variations but i keep running into various problems. This is what I'm working with right now, but I'm getting a memory access problem.
typedef struct {
int keynr;
int access;
time_t lastused;
} keycard;
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0.0;
}
int main () {
keycard *cardList = 0;
cardList = malloc(sizeof(keycard) * 1);
keyCreate(&cardList, 0);
printf("%d", cardList[0].access);
This code gives me: Exception thrown: read access violation.
cardList was 0x64.
I've been reading alot about pointers and memmory allocation but obviously i am missing something..
You if you want to duynamically add new cards to the array, you need to wrap it in another data structure:
typedef struct
{
int keynr;
int access;
time_t lastused;
} keycard;
typedef struct
{
keycard *keyarray;
size_t size;
}keystorage;
int keyCreate(keystorage *cardList, size_t keyid)
{
if (cardList -> keyarray == NULL || keyid + 1 > cardList -> size)
{
keycard *new = realloc(cardList -> keyarray, sizeof(*(cardList -> keyarray)) * (keyid + 1));
if(!new) return -1; //error
cardList -> keyarray = new;
cardList -> size = keyid + 1;
}
cardList -> keyarray[keyid].keynr = keyid + 100;
cardList -> keyarray[keyid].access = 1;
cardList -> keyarray[keyid].lastused = 0.0;
return 0; //OK
}
int main (void) {
keycard key;
keystorage cards = {NULL, 0};
keyCreate(&cards, 500);
printf("%d", cards.keyarray[500].access);
return 0;
}
You are passing the incorrect type to keyCreate. This function expects a pointer to keycard, but you are passing it a double pointer instead. The & means "take the address of", which turns cardList into a keyCard** type. Instead, consider the following:
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0; // time_t is most likely a signed integer
}
int main (void) {
keycard *cardList = malloc(sizeof(keycard) * 1);
// always check if malloc succeeds, and if it does not, handle the error somehow
if (cardList == NULL)
{
fprintf(stderr, "Insufficient mem\n");
return -1;
}
keyCreate(cardList, 0);
printf("%d\n", cardList[0].access); // the \n will flush the output and
// put each item on its own line
// cleanup when you're done, but the OS will do this for you when the
// process exits also
free(keyCreate);
return 0;
}
Also, time_t is most likely a signed integer (What is ultimately a time_t typedef to?), so assigning it to 0.0 is probably not right, but you'll need to check what it typedefs to on your system.
Finally, I assume this is just an MCVE, but I'd advise against mallocing in this case. The 2 primary reasons to malloc are when you don't know how much data you'll need until runtime, or you need "a lot" of data. Neither of those are true in this case. Just from what you've presented, I'd probably do the following:
#define NUM_KEY_CARDS 1
void keyCreate(keycard *cardList, int keyid) {
cardList[keyid].keynr = keyid + 100;
cardList[keyid].access = 1;
cardList[keyid].lastused = 0; // time_t is most likely a signed integer
}
int main (void) {
keycard cardList[NUM_KEY_CARDS];
for (int keyid=0; keyid<NUM_KEY_CARDS; keyid++)
{
keyCreate(cardList+keyid, keyid);
// or keyCreate(&(cardList[keyid]), keyid);
printf("%d\n", cardList[keyid].access);
}
return 0;
}
Related
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
The following code works fine without the statement d = *dummy; which is a double pointer dereference. However if this line is present, a segmentation fault occurs. Why so?
The code allocates and initializes memory for data structs dynamically. I was trying to simplify access to the returned pointer-to-pointer.
#include <stdlib.h>
#include <stdio.h>
typedef struct s_dummy {
char dummy_number;
} Dummy;
int mock_read_from_external_source() {
return 4;
}
int load_dummies(Dummy** dummies, int* num_of_dummies) {
*num_of_dummies = mock_read_from_external_source();
*dummies = (Dummy*) calloc(*num_of_dummies, sizeof(Dummy));
if (!dummies) {
return 1; // allocation unsuccessful
}
// Iterate dummies and assign their values...
for (int i = 0; i < *num_of_dummies; i++) {
(*dummies + i)->dummy_number = i;
}
return 0;
}
void main() {
Dummy** dummies;
Dummy* d;
int num_of_dummies = 0;
int *p_num_of_dummies = &num_of_dummies;
int err;
err = load_dummies(dummies, p_num_of_dummies);
// Segmentation fault occurs when dummies is dereferenced
d = *dummies;
if (err) {
exit(err);
}
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", (*dummies + i)->dummy_number);
}
}
Thanks in advance.
You are getting the fault because of UB, in part caused by trying to use variable objects without memory. dummies, although created as a Dummies **, has never been provided memory. At the very least, your compiler should have warned you about dummies not being initialized in this call:
err = load_dummies(dummies, p_num_of_dummies);
This is easily addressed by simply initializing the variable when it is created:
Dummy** dummies = {0}; //this initialization eliminates compile time warnings
^^^^^
Then come the run-time errors. The first is called a fatal run-time on my system, which means the OS refused to continue because of a serious problem, in this case an attempt to dereference a null pointer in this line:
dummies = (Dummy) calloc(*num_of_dummies, sizeof(Dummy));
Because you created a Dummy ** called dummies, the first step is to create memory for the pointer to pointers dummies, then create memory for the several instances of dummies[i] that will result. Only then can the members of any of them be written to.
Here is one method illustrating how memory can be created for a Dummies pointer to pointers, ( d ) and several Dummies instances ( d[i] ):
Dummy ** loadDummies(int numPointers, int numDummiesPerPointer)
{
int i;
Dummy **d = {0};
d = malloc(numPointers * sizeof(Dummy *));//Create Dummies **
if(!d) return NULL;
for(i=0;i<numPointers;i++)
{ //Now create Dummies *
d[i] = malloc(numDummiesPerPointer*sizeof(Dummy)); //random size for illustration
if(!d[i]) return NULL;
}
return d;
}
In your main function, which by the way should really be prototyped at a minimum as: int main(void){...}, this version of loadDummies could be called like this:
...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...
After using this collection of dummies, be sure to free all of them in the reverse order they were created. Free all instances of dummies[0]-dummies[numPointers-1] first, then free the pointer to pointers, dummies
void freeDummies(Dummy **d, int numPointers)
{
int i;
for(i=0;i<numPointers;i++)
{
if(d[i]) free(d[i]);
}
if(d) free(d);
}
Called like this:
freeDummies(dummies, 4);
dummies was never assigned a value, so de-referencing will attempt to reach some random memory which is almost certainly not going to be part of your program's allocated memory. You should have assigned it to &d.
But you don't even need to do that. Just use &d once when you call the function.
Also, if you return the number of dummies allocated instead of 1/0, you can simplify your code. Something like the below (not tested):
#include <stdio.h>
int mock_read_from_external_source() {
return 10;
}
typedef struct Dummy {
int dummy_number;
} Dummy;
int load_dummies(Dummy** dummies) {
int want, i = 0;
if((want = mock_read_from_external_source()) > 0) {
*dummies = (Dummy*) calloc(want, sizeof(Dummy));
if(*dummies) {
// Iterate dummies and assign their values...
for (i = 0; i < want; i++) {
(*dummies)[i].dummy_number = i;
}
}
}
return i;
}
int main() {
Dummy* d = NULL;
int num_of_dummies = load_dummies(&d); // when &d is de-referenced, changes are reflected in d
if(num_of_dummies > 0) {
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", d[i].dummy_number);
}
}
if(d) { // clean up
free(d);
}
return 0;
}
I trying to use a dynamic array, when i finish using it, i try to free the memory used and i get this error.
free(): invalid next size (fast): 0x00652098
This are the declarations of the struct variables:
struct player {
int played_time;
int min_time;
int max_time;
int errors;
int color;
};
struct Players {
struct player *array;
size_t player_number;
size_t size;
};
typedef struct Players Player_list;
This are the method used to manage the dynamic array:
void initArray(Player_list *list, size_t initialSize) {
list->array = (struct player *) malloc(initialSize * sizeof(struct player));
list->player_number = 0;
list->size = initialSize;
}
void insertArray(Player_list *list, struct player element) {
if (list->player_number == list->size) {
list->size *= 2;
list->array = (struct player *) realloc(list->array,
list->size * sizeof(struct player));
}
list->array[list->player_number++] = element;
}
void freeArray(Player_list *list) {
free(list->array);
list->array = NULL;
list->player_number = list->size = 0;
}
int disqualified(Player_list *list, int errors) {
int i = 0;
for (i = 0; i < list->player_number; i++) {
if (list->array[i].errors >= errors) {
return 1;
}
}
return 0;
}
And here is how i use it in the main:
/**
* When button is pressed 1 add an error to a random player
*/
void button_s_isr(void) {
int index = rand() % (players.player_number);
point_players->array[index].errors = point_players->array[index].errors + 1;
}
...
int main(void) {
...
// set up of GPIO
// get with scanf NUMBER_OF_PLAYERS and MAX_ERRORS values
int i;
for (i = 0; i < NUMBER_OF_PLAYERS; i++) {
struct player player;
player.color = PLAYER_COLORS[i];
player.errors = 0;
player.max_time = 0;
player.min_time = 0;
player.played_time = 0;
insertArray(&players, player);
}
while (disqualified(&players, MAX_ERRORS) != 1) {
// wait
}
printf("\n Se ha acabdo el juego: ");
freeArray(point_players);
return EXIT_SUCCESS;
}
I must say i am quite new to C, sorry if it is difficult to understand.
What i want to do is a dynamic list of struct (players), where each player has own parameters (played_time, min_time , max_time, errors, color). And inside the main i want to have a game where i can control this parameters from each player.
Any help to improve the code is appreciated.
the posted code:
does not compile
is missing definitions for PLAYER_COLORS[i], which is a bad idea to use as the number of players could exceed the available colours in the array.
incorrectly calculates the size needed for the realloc()
fails to check the returned values from functions like malloc() and realloc()
contains a confusing (even for the OP) naming of variables and struct instances
is missing the definition for num_jugadores
incorrectly tries to assign a struct rather than copying the struct
fails to declare an instance of struct Players
and now, corrected code that compiles cleanly:
caveat: not fully tested
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // memcpy()
struct player
{
int played_time;
int min_time;
int max_time;
int errors;
int color;
};
struct Players
{
struct player *array;
size_t player_number;
size_t numPlayers;
};
//This are the method used to manage the dynamic array:
void freeArray(struct Players *pArray)
{
free(pArray->array);
pArray->array = NULL;
pArray->player_number = pArray->numPlayers = 0;
}
void initArray( struct Players *pArray )
{
if( NULL == (pArray->array = malloc(sizeof(struct player)) ) )
{ // then malloc failed
freeArray( pArray );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
pArray->player_number = 0;
pArray->numPlayers = 1;
}
size_t sizeof_array(size_t size)
{
return size * sizeof(struct player);
}
void insertArray(struct Players *pArray, struct player *element)
{
if (pArray->player_number == pArray->numPlayers)
{ // then currently allocated memory for array of players is full
struct player *temp = NULL;
if( NULL == (temp = realloc(pArray->array, sizeof_array(pArray->numPlayers)*2) ) )
{ // then, realloc failed
freeArray( pArray );
exit( EXIT_FAILURE );
}
// implied else, realloc successful
pArray->numPlayers *= 2;
pArray->array = temp;
}
memcpy( &(pArray->array[pArray->player_number]), element, sizeof( struct player ) );
pArray->player_number++;
}
//and here is how i use it in the main method:
#define num_jugadores (20)
int main( void )
{
int i;
struct Players playerList;
initArray(&playerList);
for (i = 0; i < num_jugadores; i++)
{
struct player myPlayer;
//player.color = PLAYER_COLORS[i];
myPlayer.errors = 0;
myPlayer.max_time = 0;
myPlayer.min_time = 0;
myPlayer.played_time = 0;
insertArray(&playerList, &myPlayer);
}
//...
freeArray(&playerList);
} // end function: main
An error like this usually occurs because you are writing past the end of declared memory. While we could probably find the bug by carefully pouring over every line of code, valgrind would find it much faster for you.
Try compiling your code in debug mode, without optimizations, (gcc -g -O0 if you are using gcc) and run your program under valgrind (e.g., valgrind myprog -my-prog-options). It should flag the error right away.
All this assumes you are running a variant of linux. If you are using visual studio, there will probably be a similar memory checker, but I don't know what it is or how to run it.
Good Luck!
I'm working on a project where the goal is to create automatons.
Automatons are defined by a struct :
typedef struct {
int num_states;
int initial_state;
State * states;
} Automaton;
And State is another struct defining arcs between states:
typedef struct {
int num_arcs;
bool is_final;
Arc * arcs;
} State;
typedef struct {
int symbol;
int destination;
} Arc;
I create an automaton with malloc as such :
Automaton* create_automaton(void) {
Automaton * a = (Automaton *)malloc(sizeof(Automaton));
assert(a != NULL);
a->initial_state = UNDEFINED;
a->num_states = 0;
a->states = NULL;
return a;
}
So then I want to take 2 Automatons with states and arcs created with these functions :
int add_state(Automaton* a) {
State* state = (State *)realloc(a->states, (a->num_states + 1) * sizeof(State));
if(state == NULL)
exit(EXIT_FAILURE);
a->states = state;
a->states[a->num_states].num_arcs = 0;
a->states[a->num_states].is_final = FALSE;
a->states[a->num_states].arcs = NULL;
return a->num_states++;
}
void add_arc(Automaton* a, int from, int to, int symbol) {
if(from >= a->num_states || to >= a->num_states)
exit(EXIT_FAILURE);
Arc * arc = (Arc *)realloc(a->states[from].arcs, (a->states[from].num_arcs + 1) * sizeof(Arc));
if(arc == NULL)
exit(EXIT_FAILURE);
a->states[from].arcs = arc;
a->states[from].arcs[a->states[from].num_arcs].destination = to;
a->states[from].arcs[a->states[from].num_arcs].symbol = symbol;
a->states[from].num_arcs++;
}
I want to combine these 2 Automatons in one so I wrote this function:
Automaton* append_automaton(Automaton * a1, Automaton * a2)
{
Automaton * a = copy_automaton(a1);
int i = 0;
for(i = 0; i < a2->num_states; i++)
{
add_state(a);
a->states[a1->num_states + i] = a2->states[i];
for(j = 0;j<a->states->num_arcs;j++)
{
a->states[i].arcs[j].destination =+ a2->num_states;
}
}
a->initial_state = a1->initial_state;
return a;
}
However I can create the Automaton, add states and arcs to it without any problem, when i try to merge them together with append_automaton I get a segmentation fault when in add_state() I realloc State to fit one more state in the new automaton.
So my question is the following : Why is realloc giving me a segmentation fault when in this function (append_automaton) althought it works perfectly outside of it?
PS: copy_Automaton() does indeed overwrite the create_Automaton() so I removed the line: Automaton * a = create_automaton() in append_automaton()
And here is copy_automaton():
Automaton* copy_automaton(Automaton* a) {
int i = 0;
Automaton * cp_a = malloc(sizeof(Automaton));
cp_a->states = malloc(sizeof(a->states));
for(i = 0; i < a->num_states; i++)
{
cp_a->states[i].arcs = malloc(sizeof(a->states[i].arcs));
cp_a->states[i] = a->states[i];
}
cp_a->num_states = a->num_states;
cp_a->initial_state = a->num_states;
//memcpy(a, cp_a, sizeof(Automaton));
return cp_a;
}
The problem I see is your are updating a->num_states after the for cycle. However a->num_states it is used inside the cycle in the function add_state(a);
You need to put (a->num_states)++ inside the loop.
Hello world (hi people),
First, I'd say this is my first post, so please be clement.
As the title says, I've a heap corruption when I wants to free my object(s). I passed a couple of hours trying to fix it but I just can't see what's wrong even though I'm sure it's obvious!
So that's why I come to you.
My goal is to create some functions to (poorly) mimic some std::vector function in C. All objects are dynamically created. The implementation may be tricky due to the massive use of pointers.
I got the heap corruption when I free the vector object but I don't know if it comes from the pushBack or the destroy function.
Feel free to ask more information. Constructive comments are welcome!
Here is some piece of code:
Header content:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct _array
{
unsigned int size;
int *pData;
} tArray, *ptArray;
typedef struct _vector
{
unsigned int size;
ptArray *pData;
} tVector, *ptVector;
ptArray createArray(unsigned int size);
void destroyArray(ptArray *pArray);
ptVector createVector();
int pushBackArray(ptVector pVector, ptArray pArrayToAppend);
int popBackArray(ptVector pVector);
void destroyVector(ptVector *pVector);
Main content:
int main(char argc, char *argv[])
{
unsigned int size = 5, i;
time_t seed = NULL;
ptArray pArr = createArray(size);
ptVector pVec = createVector();
srand(seed);
for(i = 0; i < pArr->size; i++)
{
pArr->pData[i] = rand() % 9 + 1;
}
//destroyVector(&pVec); // Works at this point
pushBackArray(pVec, pArr);
destroyArray(&pArr);
destroyVector(&pVec); // Heap corruption on free pVector->pData
getchar();
return 0;
}
Body content:
ptArray createArray(unsigned int size)
{
ptArray pArray = (ptArray)calloc(1, sizeof(tArray));
if(pArray)
{
pArray->pData = (int*)malloc(size * sizeof(int));
if(pArray->pData)
pArray->size = size;
}
return pArray;
}
void destroyArray(ptArray *pArray)
{
if(pArray)
{
free((*pArray)->pData);
free((*pArray));
(*pArray) = NULL;
}
}
ptVector createVector()
{
ptVector pVector = (ptVector)calloc(1, sizeof(*pVector));
return pVector;
}
int pushBackArray(ptVector pVector, ptArray pArrayToAppend)
{
int res = 0;
if(pVector && pArrayToAppend)
{
pVector->pData = (ptArray*) realloc(pVector->pData
, sizeof(ptArray) * pVector->size + 1);
if(pVector->pData)
{
pVector->pData[pVector->size] = createArray(pArrayToAppend->size);
if(pVector->pData[pVector->size])
{
memcpy(pVector->pData[pVector->size]->pData
, pArrayToAppend->pData
, pVector->pData[pVector->size]->size * sizeof(int));
pVector->size++;
}
else
{
pVector->pData = (ptArray*) realloc(pVector->pData
, sizeof(ptArray) * pVector->size);
res = 3;
}
}
else
res = 2;
}
else
res = 1;
return res;
}
void destroyVector(ptVector *pVector)
{
if(pVector)
{
unsigned int i;
for(i = 0; i < (*pVector)->size; i++)
destroyArray( &((*pVector)->pData[i]) );
free((*pVector)->pData); // Heap Corruption throw
free(*pVector);
(*pVector) = NULL;
}
}
specifying the size is incorrect at function pushBackArray
sizeof(ptArray) * pVector->size + 1
to
sizeof(ptArray) * (pVector->size + 1)