Pointers in C is a very hard subject for me. This is part of a code from my homework and it reproduces the problem that I am having.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <crtdbg.h>
#define MAX_SONGS_PER_USER 10
#define MAX_USERS 5
#define MAX_ARTISTS 100
#define NUM_TEST_USERS 7
// This struct represents a song in the system
typedef struct {
char *title;
char *artist;
short int duration;
char downloaded;
} Song;
// This struct represents a user in the system
typedef struct {
char *name;
char online; // 1 = YES, 0 = NO
Song *songs[MAX_SONGS_PER_USER]; // songs this user has
short int numSongs; // number of songs this user has
} User;
// This structure represents the Tune Share system
typedef struct {
User *users[MAX_USERS]; // An array of all registered users
short int numUsers;
} TuneShare;
int registerUser(TuneShare *t, char *name)
{
short int numUsers = t->numUsers;
if (numUsers == MAX_USERS)
{
return 0;
}
else
{
if(numUsers >= 1)
//printf("%s \n", t->users[0]->name);
for (int i = 0; i < numUsers; i++)
{
User *u = t->users[i];
char *uName = u->name;
if (uName == name)
{
return 0;
}
//free(u);
}
User *temp;
if ((temp = malloc(sizeof *temp)) != NULL)
{
temp->name = name;
temp->numSongs = 0;
temp->online = '0';
}
t->users[numUsers] = temp;
t->numUsers = numUsers + 1;
return 1;
}
}
int addSong(User *u, char *title, char *artist, short int duration)
{
short int numSongs = u->numSongs;
if (numSongs == MAX_SONGS_PER_USER)
{
return 0;
}
else
{
if (numSongs >= 1)
for (int i = 0; i < numSongs; i++)
{
if (u->songs[i]->title == title)
{
return 0;
}
}
Song *temp;
if ((temp = malloc(sizeof *temp)) != NULL)
{
temp->title = title;
temp->artist = artist;
temp->duration = duration;
}
u->songs[numSongs] = temp;
u->numSongs = numSongs + 1;
//free(temp);
return 1;
}
}
void logon(TuneShare *t, char *name)
{
User *u = userWithName(t, name);
if (u != NULL)
{
u->online = '1';
}
}
void displayStats(TuneShare *t)
{
printf("\nTune Share Center (%d registered users)\n", t->numUsers);
short int numOnline = 0, numSongs = 0;
User **u = onlineUsers(t, &numOnline);
Song **s = allAvailableSongs(t, &numSongs);
printf("\n%d Online Users:\n", numOnline);
if (numOnline == 0)
{
printf("\tNONE\n\n");
}
else
{
for (int i = 0; i < numOnline; i++)
{
printf("\t%s with %d songs as follows:\n", u[i]->name, u[i]->numSongs);
for (int j = 0; j < u[i]->numSongs; j++)
{
printf("\t\t\"%s\" by %s\n", u[i]->songs[j]->title, u[i]->songs[j]->artist);
}
}
}
printf("\n%d Available Songs:\n", numSongs);
if (numSongs == 0)
{
printf("\tNONE\n\n");
}
else
{
for (int i = 0; i < numSongs; i++)
{
int min = s[i]->duration / 60;
int sec = s[i]->duration % 60;
if(sec > 10)
printf("\t\"%s\" by %s (%d:%d)\n", s[i]->title, s[i]->artist, min, sec);
else
printf("\t\"%s\" by %s (%d:0%d)\n", s[i]->title, s[i]->artist, min, sec);
}
}
printf("\n");
}
int main() {
// This is test data
static char *TITLES[] = { "Back 2 Life", "Loneliness For Love", "Desire 126", "Perfect", "In My Head",
"Old Skool Love", "Let's Go", "No Place", "We Gotta Go", "How You Get the Girl",
"Catch", "Here Tonight", "Details", "Dangerous", "Brighter Than the Sun",
"Photograph", "Thinking Out Loud", "If Heaven Were to Fall", "I Just Wanna Be With You",
"Song Sung Blue", "Outta Style", "Why", };
static char *ARTISTS[] = { "E-Type", "Lovely the Band", "Hollerado", "Ed Sheeran", "Ryland James",
"Divine Brown", "Group 1 Crew", "Backstreet Boys", "E-Type", "Taylor Swift",
"Brett Young", "Brett Young", "Billy Currington", "Kardinal Offichall",
"Colbie Caillat", "Ed Sheeran", "Ed Sheeran", "E-Type", "E-Type", "Neil Diamond",
"Aaron Watson", "Frankie Avalon", };
static int DURATIONS[] = { 217, 237, 187, 263, 205, 204, 256, 179, 213, 247, 196,
216, 201, 251, 231, 202, 281, 223, 230, 185, 222, 161 };
static char *TEST_USER_NAMES[NUM_TEST_USERS] = { "Disco Stew", "Peter Punk", "Country Candy", "Ronnie Rocker",
"Sleeping Sam", "Disco Stew", "Mellow Marvin" };
static int LIST_SIZES[NUM_TEST_USERS] = { 7, 9, 9, 5, 1, 0, 0 };
static int SONGNUMS[NUM_TEST_USERS][MAX_SONGS_PER_USER] = {
{1, 2, 4, 5, 12, 15, 21}, {0, 1, 3, 8, 9, 13, 14, 17, 20},
{6, 7, 8, 10, 11, 12, 13, 20, 21}, {0, 8, 16, 17, 18}, {19}, {0}, {0} };
// Create the TuneShare Center
TuneShare tuneShareCenter;
tuneShareCenter.numUsers = 0;
// Attempt to register all test users
for (int i = 0; i < NUM_TEST_USERS; i++) {
if (!registerUser(&tuneShareCenter, TEST_USER_NAMES[i]))
printf("Error adding User: \"%s\"\n", TEST_USER_NAMES[i]);
else
printf("User: \"%s\" has been registered\n", TEST_USER_NAMES[i]);
}
// Display some stats
displayStats(&tuneShareCenter);
// Log on a user
printf("\nLogging on a user...\n");
logon(&tuneShareCenter, "Disco Stew");
// Display some stats
displayStats(&tuneShareCenter);
// Now add all the test songs for these test users
for (int i = 0; i < tuneShareCenter.numUsers; i++) {
for (int j = 0; j < LIST_SIZES[i]; j++)
addSong(tuneShareCenter.users[i], TITLES[SONGNUMS[i][j]], ARTISTS[SONGNUMS[i][j]], DURATIONS[SONGNUMS[i][j]]);
}
// Display some stats
displayStats(&tuneShareCenter);
}
This gives the correct output I need. Just like this.
But when I free the allocated memory from the heap using free() function as an example in the function **int registerUser(TuneShare t, char name) it does not give the output at all,
int registerUser(TuneShare *t, char *name)
{
short int numUsers = t->numUsers;
if (numUsers == MAX_USERS)
{
return 0;
}
else
{
if(numUsers >= 1)
//printf("%s \n", t->users[0]->name);
for (int i = 0; i < numUsers; i++)
{
User *u = t->users[i];
char *uName = u->name;
if (uName == name)
{
return 0;
}
//free(u);
}
User *temp;
if ((temp = malloc(sizeof *temp)) != NULL)
{
temp->name = name;
temp->numSongs = 0;
temp->online = '0';
}
t->users[numUsers] = temp;
t->numUsers = numUsers + 1;
free(temp);
return 1;
}
}
Here is the output when I use free() as above.
I do not understand what is the problem. If anyone could help me it would be amazing.
Freeing a pointer is like erasing its content from memory, so when you free temp, you are deleting the new User, so t->users (aka tuneShareCenter.users) will be full of useless "empty" User pointers.
You should free the users at the end of the main function, freeing tuneShareCenter and the songs with something like:
for (int i = 0; i < tuneShareCenter.numUsers; i++) {
User* tUser = tuneShareCenter.users[i];
for(int j = 0; j < tUser->numSongs; j++){
free(tUser->songs[j]);
}
free(tUser);
}
free(tuneShareCenter);
(I hope I wrote it correctly)