Hi I've been working on school project and need your help with the code. I use valgrind to work out what is wrong and need to get rid of the awful errors what exacly means by your thoughts
Function inserts new element into table
This is one of the errors i get
Invalid write of size 1
at 0x4C29B32: strcpy (vg_replace_strmem.c:458) by 0x401CE9: HTab_insert (ial.c:65)
by 0x4019B5: main (main.c:82) Address 0x5449785 is 0 bytes after a block of size 5 alloc'd
at 0x4C28FA4: malloc (vg_replace_malloc.c:296)
by 0x401CC9: HTab_insert (ial.c:64)
by 0x4019B5: main (main.c:82)
HTab_listitem* HTab_insert(HTab_t* ptrht, Ttoken token) {
unsigned ind = hash_function(ptrht->htable_size,token);
HTab_listitem* item_ptr = NULL;
HTab_listitem* item = ptrht->list[ind];
HTab_listitem* nextitem;
if(item == NULL) {
nextitem = malloc(sizeof(HTab_listitem)+sizeof(char)*(strlen(token.data)+1));
if(nextitem == NULL)
/*allocation error*/
return NULL;
else {
//printf("HERE\n");
//printf("%s\n", token.data);
//memcpy(nextitem->token.data,token.data,strlen(token.data)+1);
int length = strlen(token.data);
nextitem->token.data = malloc(length * sizeof((char) +2));
strcpy(nextitem->token.data,token.data);
nextitem->token.data[length] = '\0';
nextitem->token.stav = token.stav;
//printf("HERE AFTER\n");
nextitem->ptrnext = NULL;
item = ptrht->list[ind] = nextitem;
nextitem = NULL;
if(item == NULL)
return NULL;
}
}
else {
while(item != NULL) {
if(strcmp(item->token.data,token.data) == 0) {
//if found
item_ptr = item;
break;
}
else {
//next item
item_ptr = item;
item = item->ptrnext;
}
}
if(item_ptr != NULL && item != item_ptr) {
//not found insert next item
nextitem = malloc(sizeof(HTab_listitem*)+sizeof(char)*(strlen(token.data)+1));
if(nextitem == NULL)
/*allocation error*/
return NULL;
else {
//memcpy(nextitem->token.data,token.data,strlen(token.data)+1);
int length = strlen(token.data);
nextitem->token.data = malloc(length * sizeof((char) +2));
strcpy(nextitem->token.data,token.data);
nextitem->token.data[length] = '\0';
nextitem->token.stav = token.stav;
nextitem->ptrnext = NULL;
item = nextitem;
if(item == NULL)
return NULL;
item_ptr->ptrnext = item;
}
}
}
return item;
}
You have a few allocation errors that could lead to undefined behavior.
I will go into the code from top to bottom
First, you allocate to much memory
nextitem = malloc(sizeof(HTab_listitem)+sizeof(char)*(strlen(token.data)+1));
Where the following should be enough, since the nextitem->token.data is allocated afterwards.
nextitem = malloc(sizeof(HTab_listitem));
Also, when allocating token.data, use the following :
int length = strlen(token.data);
nextitem->token.data = malloc( sizeof(char) * (length + 1) );
nextitem->token.data[length] = 0;
Your second item allocation is again not the right size.
You allocate the sizeof of a pointer (8 bytes) instead of the size of your struct and adding the token.data is still not usefull.
nextitem = malloc(sizeof(HTab_listitem*)+sizeof(char)*(strlen(token.data)+1));
//Error here (HTab_listitem*)
That should be :
nextitem = malloc(sizeof(HTab_listitem));
Then again allocate token.data as done previousely.
Related
I am trying to insert Node to Binary tree. This is my function for creating Node (rest is done).
void BVSCreate_function(TNodef *rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(struct tnodef));
if (newPtr == NULL) {
fprintf(stderr, "99");
return;
}
TNodef init;
string initStr;
initStr.str = NULL;
initStr.length = 0;
initStr.alloc = 0;
newPtr = &init;
newPtr->content = &initStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
rootPtr = newPtr;
}
void BVSInsert_function(TNodef *rootPtr, function_save token) {
if (rootPtr == NULL) {
BVSCreate_function(rootPtr, token);
} else {
if ((strCmpStr(token.content, rootPtr->content)) < 0) {
BVSCreate_function(rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
BVSCreate_function(rootPtr->rightPtr, token);
}
}
}
When TNodef and function_save are structs:
typedef struct {
string *content;
int param_count;
int ret_value;
} function_save;
typedef struct tnodef {
string *content;
struct tnodef *leftPtr;
struct tnodef *rightPtr;
int parameters;
int return_type;
} TNodef;
Where string is defined as this struct:
typedef struct {
char *str; // content of string
int length; // length of string
int alloc; // amount of memory allocated
} string;
strCpystr function :
int strCpyStr(string *s1, string *s2) {
int len2 = s2->length;
if (len2 > s1->alloc) {
if (((s1->str) = (char *)realloc(s1->str, len2 + 1)) == NULL) {
return 1;
}
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2 + 1;
return 0;
}
I am trying to create a node in binary tree and put there information from struct function_save.
But when I try to print this tree after insert it shows me that tree is still empty.
Your code in BVSCreate_function has undefined behavior because:
newPtr = &init; discards the allocated node and instead uses a local structure that will become invalid as soon as the function returns.
newPtr->content = &initStr; is incorrect for the same reason: you should allocate memory for the string too or possibly modify the TNodeDef to make content a string object instead of a pointer.
Function BVSInsert_function does not return the updated root pointer, hence the caller's root node is never updated. You could change the API, passing the address of the pointer to be updated.
There is also a confusion in BVSInsert_function: it should call itself recursively when walking down the tree instead of calling BVSCreate_function.
Here is a modified version:
/* Allocate the node and return 1 if successful, -1 on failure */
int BVSCreate_function(TNodef **rootPtr, function_save token) {
TNodef *newPtr = malloc(sizeof(*newPtr));
string *newStr = malloc(sizeof(*content));
if (newPtr == NULL || newStr == NULL) {
fprintf(stderr, "99");
free(newPtr);
free(newStr);
return -1;
}
newStr->str = NULL;
newStr->length = 0;
newStr->alloc = 0;
newPtr->content = newStr;
newPtr->leftPtr = NULL;
newPtr->rightPtr = NULL;
newPtr->return_type = token.ret_value;
newPtr->parameters = token.param_count;
strCpyStr(newPtr->content, token.content);
*rootPtr = newPtr;
return 1;
}
int BVSInsert_function(TNodef **rootPtr, function_save token) {
if (*rootPtr == NULL) {
return BVSCreate_function(rootPtr, token);
} else {
if (strCmpStr(token.content, rootPtr->content) < 0) {
return BVSInsert_function(&rootPtr->leftPtr, token);
} else
if ((strCmpStr(token.content, rootPtr->content)) > 0) {
return BVSInsert_function(&rootPtr->rightPtr, token);
} else {
/* function is already present: return 0 */
return 0;
}
}
}
Note also that function strCpyStr may write beyond the end of the allocated area is len2 == s1->alloc, assuming s1->len is the length of the string, excluding the null terminator.
Here is a modified version:
int strCpyStr(string *s1, const string *s2) {
int len2 = s2->length;
if (len2 >= s1->alloc) {
char *newstr = (char *)realloc(s1->str, len2 + 1);
if (newstr == NULL) {
return 1;
}
s1->str = newstr;
s1->alloc = len2 + 1;
}
strcpy(s1->str, s2->str);
s1->length = len2;
return 0;
}
I am new to C and am trying to code up a data structure, primarily, a ternary search tree. I am working under the assumption (for now) that valid char inputs are being passed in. I am having some issues with my insert function. Note that I am also inserting the original string in the last TSTnode where the last character of str will also be held.
Here is what I have so far
struct TSTnode {
char* word; // NULL if no word ends here
char self;
struct TSTnode *left, *sub, *right;
};
int insert_tst(struct TSTnode** tree, const char* str) {
return _insert(tree, str, 0);
}
int _insert(struct TSTnode** tree, const char* str, int position) {
if((*tree) == NULL) {
*tree = new_tst_node(*(str+position));
position = position + 1;
if(*(str+position) == '\0') {
(*tree)->word = strcpy((*tree)->word,str);
return 1;
}
}
else if ((*tree)->self > *(str+position)) {
position = position + 1;
_insert( &((*tree)->left), str, position);
}
else if ((*tree)->self < *(str+position)) {
position = position + 1;
_insert( &((*tree)->right), str, position);
}
else {
position = position + 1;
_insert( &((*tree)->sub), str, position);
}
return 0;
}
struct TSTnode* new_tst_node(char self) {
struct TSTnode* newNode = (struct TSTnode*) malloc(sizeof(struct
TSTnode));
if (newNode == NULL) {
return NULL;
}
newNode->word = NULL;
newNode->self = self;
newNode->left = NULL;
newNode->right = NULL;
newNode->sub = NULL;
return newNode;
}
Here is how I am testing:
struct TSTnode* tree = NULL;
char* words[1] = {"hello"};
for (int i = 0; i < 1; i++) {
if (insert_tst(&tree, words[i]) == 0) {
//print some error
}
else { //success }
EDIT - My issue is that none of my conditional branches are being taken and the insert function simply goes straight to return 0.
Note: You confusingly use tree for both TSTnode* and TSTnode**. I'm going to use tree_ptr for the latter, and pretend that you did the same.
Your claim is false. The body of if((*tree_ptr) == NULL) is executed. You do have a number of problems, though.
You don't handle the case where *tree_ptr == NULL && *(str+position+1) != '\0'.
You don't correctly handle the case where *tree_ptr != NULL && *(str+position+1) == '\0'.
You always return 0 when *tree_ptr != NULL || str[1] != '\0'.
You never allocate word, but you deference it. The thing is, you shouldn't be storing the string again anyway!
You don't handle the case where str[0] == '\0' (empty string).
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
return insert_tst_helper(tree_ptr, str, 0);
}
int insert_tst_helper(struct TSTnode** tree_ptr, const char* str, int position) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*(str+position));
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (*(str+position+1) == '\0') { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
else if ((*tree_ptr)->self > *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->left), str, position);
}
else if ((*tree_ptr)->self < *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->right), str, position);
}
else {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->sub), str, position);
}
}
Untested.
Let's clean this up, though.
*(str+position)simplifies tostr[position]
ch == '\0'simplifies toch == 0then to!ch
position = position + 1; return insert_tst_helper(..., str, position);simplifies to++position; return insert_tst_helper(..., str, position);then toreturn insert_tst_helper(..., str, position+1);then toreturn insert_tst_helper(..., str+1, 0);then toreturn insert_tst(..., str+1);
Why is recursion being used at all???
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
while (1) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*str);
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (!*(str+1)) { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
int cmp = *str - (*tree_ptr)->self;
if (cmp < 0) { tree_ptr = &( (*tree_ptr)->left ); }
else if (cmp > 0) { tree_ptr = &( (*tree_ptr)->right ); }
else { tree_ptr = &( (*tree_ptr)->sub ); }
++str;
}
}
Untested.
I been banging my head on the wall with this one. I was able to narrow it down to the realloc portion of my code.
CalStatus readCalComp( FILE *const ics, CalComp **const pcomp )
{
CalStatus test;
CalProp * foldLine;
CalProp * temp;
CalComp ** subComp;
char * buffer;
static int depth = 0;
int count = 0;
int i = 0;
buffer = NULL;
foldLine = NULL;
subComp = NULL;
if (depth == 0)
{
test = readCalLine (ics, &buffer);
if (buffer == NULL)
{
return test;
}
foldLine = malloc (sizeof (CalProp));
assert (foldLine != NULL);
test.code = parseCalProp (buffer, foldLine);
free (buffer);
if ((strcmp ("BEGIN", foldLine->name) == 0) && ((strcmp ("VCALENDAR", foldLine->value) == 0)))
{
(*pcomp)->name = malloc (sizeof(char) * strlen(foldLine->value)+1);
assert ((*pcomp)->name != NULL);
strcpy((*pcomp)->name, foldLine->value);
depth = depth + 1;
free(foldLine->name);
free(foldLine->value);
free(foldLine);
while ((buffer != NULL) && (test.code == OK) && (depth > 0))
{
test = readCalLine (ics, &buffer);
if (buffer != NULL)
{
foldLine = malloc (sizeof(CalProp));
assert (foldLine != NULL);
test.code = parseCalProp (buffer, foldLine);
free (buffer);
if ((strcmp ("END", foldLine->name) == 0) && ((strcmp ("VCALENDAR", foldLine->value) == 0) || (strcmp ("VCALENDAR\r\n", foldLine->value) == 0) ))
{
depth = depth - 1;
free(foldLine->name);
free(foldLine->value);
free(foldLine);
return test;
}
else if (strcmp ("BEGIN", foldLine->name) == 0)
{
subComp = malloc(sizeof (CalComp *));
*subComp = malloc(sizeof(CalComp) + (1*sizeof(CalComp*)));
(*subComp)-> name = NULL;
(*subComp)-> nprops = 0;
(*subComp)-> prop = NULL;
(*subComp)-> ncomps = 0;
(*subComp)-> comp[0] = NULL;
(*subComp)-> name = malloc(sizeof(char) *strlen(foldLine->value)+1);
strcpy((*subComp)->name, foldLine->value);
if ((*pcomp)-> ncomps == 0)
{
(*pcomp)->comp[(*pcomp)->ncomps] = *subComp;
(*pcomp)->ncomps += 1;
}
else
{
(*pcomp)->ncomps += 1;
*pcomp = realloc(*pcomp, sizeof(CalComp) + (2*sizeof(CalComp*)));
(*pcomp)->comp[(*pcomp)->ncomps-1] = *subComp;
}
depth = depth + 1;
test = readCalComp (ics, subComp);
}
} // end of if buffer NULL
}// end of While
} // end of if VCALENDAR
} // End of if Depth
else
{
if (count == 0)
{
test = readCalLine (ics, &buffer);
count += 1;
}
while ((test.code == OK) && (buffer != NULL))
{
if (count != 1)
{
test = readCalLine (ics, &buffer);
}
else
{
count = 0;
}
if (buffer != NULL)
{
foldLine = malloc (sizeof(CalProp));
test.code = parseCalProp (buffer, foldLine);
free (buffer);
if ((strcmp ("END", foldLine->name) == 0) && ((strcmp ((*pcomp)->name, foldLine->value) == 0)))
{
depth = depth - 1;
free (foldLine->name);
free (foldLine->value);
free (foldLine);
return test;
}
else if (strcmp ("BEGIN", foldLine->name) == 0)
{
printf("Success in malloc 2!\n");
subComp = malloc(sizeof (CalComp *));
*subComp = malloc(sizeof(CalComp) + (1*sizeof(CalComp*)));
(*subComp)-> name = NULL;
(*subComp)-> nprops = 0;
(*subComp)-> prop = NULL;
(*subComp)-> ncomps = 0;
(*subComp)-> comp[0] = NULL;
(*subComp)-> name = malloc(sizeof(char) *strlen(foldLine->value)+1);
strcpy ((*subComp)->name, foldLine->value);
if ((*pcomp)-> ncomps == 0)
{
(*pcomp)->comp[(*pcomp)->ncomps] = *subComp;
(*pcomp)->ncomps += 1;
}
else
{
(*pcomp)->ncomps += 1;
(*pcomp) = realloc(*pcomp, sizeof(CalComp) + (2*sizeof(CalComp*)));
(*pcomp)->comp[(*pcomp)->ncomps-1] = *subComp;
printf ("First subcomponent is %s\n", (*pcomp)->comp[0]->name);
printf ("Second subcomponent is %s\n", (*pcomp)->comp[1]->name);
}
depth = depth + 1;
test = readCalComp (ics, subComp);
}
}
}
}
return test;
}
CalComp is a struct that consists of:
char * name;
int numProps;
CalProp *prop (linked list);
int numComp;
CalComp *comp[] (flexible array);
Checking inside the function, the name of the structs within the flexible array is correct, but when I try to access the names outside of the function, it either NULL value or been set to the name of the first linked list node of the structure.
Due to the nature of the assignment, I can not modify Calcomp struct nor the function parameters. The function must be recursive, and the flexible array must adjust based on need.
As I said before, I narrowed it down to the realloc, by printing out the values within the flexible array. The bug occurs when the program reallocs.
FYI, I have tried reallocing to a temp variable, checked to see if NULL and then assigned that one to pcomp but didn't help.
When you call realloc, you're not including ncomp in the additional size for the flexible structure, you're just hard-coding it to 2.
(*pcomp) = realloc(*pcomp, sizeof(CalComp) + (*pcomp->ncomps * sizeof(CalComp*)));
(*pcomp) = realloc(*pcomp, sizeof(CalComp) + (2*sizeof(CalComp*)));
change above line to
pcomp = realloc(*pcomp, sizeof(CalComp) + (2*sizeof(CalComp*)));
this is the function that i am calling from main:
char** readTokens(char *userInput, const char *seperator)
{
char** c;
char line1[512],line2[512];
int wordCount = 0;
int index;
char* tmp;
strcpy(line1, userInput);
for (index=0;line1[index]!='\n';index++);
line1[index]='\0';
strcpy(line2,line1);
tmp = strtok(line1,seperator);
while (tmp!=NULL)
{
tmp=strtok(NULL,seperator);
wordCount = wordCount + 1;
}
if((wordCount) == ERROR)
{
return NULL;
}
c=(char**)malloc(((wordCount)+1)*sizeof(char*));
if (c == NULL)
{
printf("failed to allocate memory.\n");
return NULL;
}
tmp = strtok(line2,seperator);
index=0;
while (tmp!=NULL)
{
c[index]=(char*)malloc((strlen(tmp)+1*sizeof(char)));
if (c[index]==NULL)
{
printf("failed to allocate memory.\n");
return NULL;
}
strcpy(c[index],tmp);
tmp=strtok(NULL,seperator);
index++;
}
c[index] = NULL;//put NULL on last place
return c;
}
And this how i use it in main:
while (fgets(words, sizeof(words), filePointer) != NULL) // this line is a command of reading a line from the file.
{
/*here i am calling the function*/
array = readTokens(words, " ");
theGraph->graphEdges[index_i].sourceVertex = array[ZERO];
theGraph->graphEdges[index_i].destinationVertex = array[ONE];
theGraph->graphEdges[index_i].arcValue = atoi(array[TWO]);
for(index_j = ZERO ; index_j < vertexes ; index_j++)
{
if(theGraph->placeInTableIndex[index_j] == NULL)
{
theGraph->placeInTableIndex[index_j] = array[ZERO];
break;
}
else if(strcmp(theGraph->placeInTableIndex[index_j],array[ZERO]) == ZERO)
break;
}
for(index_j = ZERO ; index_j < vertexes ; index_j++)
{
if(theGraph->placeInTableIndex[index_j] == NULL)
{
theGraph->placeInTableIndex[index_j] = array[ONE];
break;
}
else if(strcmp(theGraph->placeInTableIndex[index_j],array[ONE]) == ZERO)
break;
}
theGraph->graphEdges[index_i+ONE].sourceVertex = array[ONE];
theGraph->graphEdges[index_i+ONE].destinationVertex = array[ZERO];
theGraph->graphEdges[index_i+ONE].arcValue = atoi(array[TWO]);
index_i+= TWO;
//freeTokens(array);
}
I tried to do free to the array in the end of the while but it not work i still have memory leak from this function (valgrind check). i am using this function to free:
void freeTokens(char** tokens)
{
while(*tokens != NULL)
{
*tokens = NULL;
free(*tokens);
*tokens++;
}
tokens = NULL;
free(tokens);
}
You're losing the original value of tokens (the thing you need to free) by incrementing it; then you set it to NULL, then try to free NULL.
Instead:
void freeTokens(char** tokens)
{
char **freeTokens = tokens;
while (*freeTokens != NULL)
{
free(*freeTokens);
*freeTokens = NULL; // not actually necessary, but must happen *after* if at all
freeTokens++;
}
free(tokens);
// tokens = NULL; // accomplishes nothing; doesn't change the caller's version
}
I have the following data types:
formation.h
typedef struct formation_t {
Player players[FORMATION_NUM_PLAYERS];
int numPlayers; /* How many players are in the above array */
int timesPlayed;
int timesWon;
}* Formation;
team.h
typedef struct team_t {
char* name;
char* coachName;
Formation* formations;
int currFormations;
int maxFormations;
}* Team;
And the following functions:
Team teamCreate(char* name, char* coach, int maxFormations)
{
//Check if parameters make sense.
if (name == NULL || coach == NULL || maxFormations < 1)
{
return NULL;
}
//Try allocating memory for name.
char* teamName = malloc(strlen(name) + 1);
if (teamName == NULL)
{
return NULL;
}
strcpy(teamName, name);
//Try allocating memory for coachName.
char* coachName = malloc(strlen(coach) + 1);
if (coachName == NULL)
{
free(teamName);
return NULL;
}
strcpy(coachName, coach);
//Try allocating memory for formations.
Formation* formations = malloc(sizeof(Formation) * maxFormations);
if (formations == NULL)
{
free(teamName);
free(coachName);
return NULL;
}
//Try allocating memory for team.
Team newTeam = malloc(sizeof(struct team_t));
if (newTeam == NULL)
{
free(teamName);
free(coachName);
free(formations);
return NULL;
}
//Initialize newly created team.
newTeam->name = teamName;
newTeam->coachName = coachName;
newTeam->maxFormations = maxFormations;
newTeam->currFormations = 0;
//Return created team.
return newTeam;
}
TeamResult teamAddFormation(Team team, Formation formation)
{
//Check for TEAM_NULL_ARGUMENT.
if (team == NULL | formation == NULL)
{
return TEAM_NULL_ARGUMENT;
}
//Check for TEAM_IS_FULL.
if (team->currFormations == team->maxFormations)
{
return TEAM_IS_FULL;
}
//Add formation.
printf("\n -about to clone- \n");
team->formations[team->currFormations] = formationClone(formation);
printf("\n -clone completed- \n");
team->currFormations = team->currFormations + 1;
return TEAM_SUCCESS;
}
Formation formationClone(Formation formation)
{
if (formation == NULL)
{
return NULL;
}
Formation newFormation = malloc(sizeof(struct formation_t));
if (newFormation == NULL)
{
return NULL;
}
*newFormation = *formation;
return newFormation;
}
When I try to test my work using the following code, I get a segmentation fault right after "about to clone".
Team team = teamCreate("Ac Milan", "Carletto", 2);
Formation formation1 = formationCreate();
ASSERT_NULL_ARGUMENT(teamAddFormation(NULL, formation1));
ASSERT_SUCCESS(teamAddFormation(team, formation1));
In teamCreate() you never set your formations local variable into your Team structure after allocating it.
This is first:
//Try allocating memory for formations.
Formation* formations = malloc(sizeof(Formation) * maxFormations);
if (formations == NULL)
{
free(teamName);
free(coachName);
return NULL;
}
then you do this after allocation the host-object:
//Initialize newly created team.
newTeam->name = teamName;
newTeam->coachName = coachName;
newTeam->maxFormations = maxFormations;
newTeam->currFormations = 0;
//Return created team.
return newTeam;
You never save the formation pointer to the structure member, so that pointer member is indeterminate and using it is invoking undefined behavior.
Add this to the bottom of that stack of assignments:
newTeam->formations = formations;
//Try allocating memory for name.
char* teamName = malloc(strlen(name) + 1);
if (teamName == NULL)
{
return NULL;
}
strcpy(teamName, name);
teamName is pointing to an alocated char array. This array never deleted. This lead to a memory leak.