I got the _CrtIsValidHeapPointer(pUserData) Message when compiling my Code in VS2012 (C).
I realized I was trying to use the realloc
on the pointer so when I read other posts, many suggested using memcpy
and const char **
. I really love to do so but I just do not know how.
First Fragment of Code: Typedef struct of the Pointer that I am using to realloc
int clientcounter = 0; //Global variable since this will be needed in other functions
typedef struct client{
char name[254];
int birthday;
int landline;
int cellphone;
int clientnum;
struct client *next;
}clientdata;
My program reads the content of the file and stores it to these variables through Singly linked-list.
Second Fragment of Code:
void loading_file(clientdata curr[])
{
clientdata *dummy[10000] = {0};
clientdata *head;
clientdata *tail;
head = NULL;
tail = NULL;
//.... Asking for roster file
//.. memory allocation of dummy[clientcounter]
//.... Storing data to variables
if (head == NULL)
{
head = dummy[clientcounter];
}
else
{
tail->next=dummy[clientcounter];
}
tail = dummy[clientcounter];
if (head!=NULL)
{
dummy[clientcounter-1] = head;
do {
printf("\n ::%s:: Name\n",dummy[clientcounter]->name);
curr[clientcounter] = dummy[clientcounter];
dummy[clientcounter] = realloc(dummy,sizeof(item*) * clientcounter); //Error appears Here
dummy[clientcounter] = NULL;
clientcounter++;
dummy[clientcounter] = dummy[clientcounter-1]->next;
}while(dummy[totalitem] != NULL);
}
free(dummy[totalitem-1]);
}
Someone told me that everytime when clientcounter++
happens, I have to reallocate the memory so that it won't leak. My problem is, I know what causes the error (reallocating the pointer) but I do not know how to fix it.
Can anyone teach me how to fix the code?
If the end-goal is to simply load a file of data into a linked list, most of the posted code is extraneous and simply not needed. Following is a very simple implementation of loading a data file into a forward linked list.
What Is Needed
The general algorithm is this:
The last step is the core of the above code, and I'll explain how it works after the code. this modified function takes the file name being processed as the only input parameter, and returns a linked list of clientdata
items, the parsing of which you still have to write, so don't think you're getting all of this for free:
The Code
clientdata* load_file(const char fname[])
{
FILE *fp = fopen(fname, "r");
char line[512]; // suitable value
// pp always holds the *address* of the pointer where the
// next node will be added to the list. notice how it first
// holds the address of our list-head pointer.
clientdata *result = NULL;
clientdata **pp = &result;
while (fgets(line, sizeof(line), fp))
{
clientdata val = {0};
//
// TODO: parse line into val-members using things like
// sscanf(), strtok(), or others, etc.
//
if (parsed-successfully-condition)
{
// allocate a new list node, copy over the data
*pp = malloc(sizeof(**pp));
if (*pp)
{
memcpy(*pp, &val, sizeof(**pp));
// load pp with the address of the 'next' member for
// the node we just allocated and saved. it will be
// the link to the next new node if we need one
pp = &(*pp)->next;
}
else
{ // malloc() failed. not good. no sense in continuing.
perror("Failed to allocate new node.");
break;
}
}
}
// required. this terminates the list.
*pp = NULL;
return result;
}
The Explanation
We keep two pointers. One is the return result pointer (result
) and is initially NULL. The other is a pointer-to-pointer, pp
, that initially holds the address of our return result pointer. This is a special variable. It is a pointer-to-pointer that will always hold the address of the next pointer we need to set when making a new allocation. A picture speaks a thousand words. The initial configuration looks like this:
result = NULL;
^---- pp
When we insert a new node we populate whatever pointer who's address is being held in pp. The first time that address will be pointing to result
. Note the dereference, *pp
. So after adding a new node, then moving the address of the new node's next
pointer in to pp
, the picture now looks like this:
result --> item0
next
pp --------^
And after the second insertion
result --> item0
next --> item1
next
pp -----------------^
And finally one more...
result --> item0
next --> item1
next --> item2
next
pp --------------------------^
The algorithm finishes by terminating the list. This is done by setting the pointer addressed by pp
to NULL. Note the wording there. We are NOT setting pp
to NULL (that would be pointless). We're setting the pointer it addresses to NULL.
*pp = NULL;
The resulting picture would finish like this:
result --> item0
next --> item1
next --> item2
next --> NULL
In each case the insertion mantra is always the same.
*pp
pp
*pp
to NULL, since it is the last next
pointer in our chain, and should be NULL to terminate the linked list.There are some interesting base-conditions that are worth understanding. A notable one is "What happens when the input file has no items? Does this still work?" Yes, indeed it does. In that case the while-loop will never add a new item, pp
will still contain the address of result
, and *pp = NULL;
will (redundantly) set it to NULL. The result will be a NULL return value, exactly what you want for a linked list that is "empty".
I strongly suggest running this in a debugger to see how pp
, *pp
, and **pp
work in this algorithm.