pointers with structs in structs c - c

I have tried to create a CD struct like :
typedef struct
{
char* nameCD;
int yearOfpublication;
song* listOfSongs;
int priceCD;
int numberOfSongs;
} CD;
and I have a song struct :
typedef struct
{
char* nameSong;
char* nameSinger;
int lenghtOfSong;
} song;
void SongInput(song *psong, CD *pcd)
{
pcd->numberOfSongs++;
pcd->listOfSongs = (song*)malloc(pmcd->numberOfSongs*sizeof(song));
// here all the code that update one song..
but what should I write to update the next song?
how do I change it into an array which update the number of the songs and how can I save all the songs?
I tried this :
printf("Enter lenght Of Song:");
scanf("%d", &psong->lenghtOfSong);
but I don't understand the pointers..
and how to update the next song?
}
void CDInput(CD *pcd)
{
int numberOfSongs = 0;
//here all the other update of cd.
//songs!!!!!!!!!!!!!!!!!!!!!!!!!!!!
pcd->numberOfSongs = 0;
pcd->listOfSongs = (song*)malloc(numberOfSongs*sizeof(song));
}
Do I need to write anything else?

void CDInput(CD *pcd)
{
int i;
//...
printf("Enter number Of Song:");
scanf("%d", &pcd->numberOfSongs);
pcd->listOfSongs = (song*)malloc(pcd->numberOfSongs*sizeof(song));
for(i = 0; i < pcd->numberOfSongs; ++i){
SongInput(&pcd->listOfSongs[i]);
}
//...
}

It depends on if you want to write the structure once completely or you really want to add one item.
For the first case, please refer to BLUEPIXY's answer, for the second one, thigs are slightly more complicated.
bool add_song(song *psong, CD *pcd)
{
song* newone = realloc(pcd->listOfSongs, (pmcd->numberOfSongs+1)*sizeof(song));
if (!newone) {
// return and complain; the old remains intact.
return false; // indicating failure.
}
// now we can assign back.
pcd->listOfSongs = newone;
newone[pcd->numberOfSongs++] = *psong;
return true; // indicating success.
}

Related

String in structure gets deleted

I'm working on the last exercise of the "Think like a computer scientist, C version" book and I have some trouble with one particular point.
The exercise consists of making a small game, where the computer picks a random value between 0 and 20 and then asks me to guess the number.
After that, the computer counts the number of tries I made and, if I get a better score than the previous party, I need to store my name and the number of tries in a structure.
My problem is the following: When I restart the game, the string value, player_name, in the structure gets somehow deleted but player_score is still there.
First, I made a "call by value" function to create the structure and then a tried with a "call by reference" but getting the same results.
I think I tried everything I could with my actual knowledge for now; so, if someone could check my code and give me some tips about what's wrong I would much appreciate it!
//HEADERS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FALSE 0
#define TRUE 1
//TYPEDEF STRUCTS
typedef struct
{
int player_score;
char *player_name;
} HS_Player;
//FUNCTION PROTOTYPES
int Random_Value(void);
int Get_User_Choice(void);
int Check_Result(int computer, int my_choice);
int Try_Again(int game_result, int computer);
void Player_Infos(HS_Player *player_p, int score);
int Game_Restart(void);
//MAIN
int main(void)
{
int end_game;
int high_score_value = 100;
HS_Player player;
while (end_game != TRUE)
{
int computer_number = Random_Value();
printf("Guess the number between 0 et 20 chosen by the computer.\n");
int your_number = Get_User_Choice();
int result_game = Check_Result(computer_number, your_number);
int tries_to_win = Try_Again(result_game, computer_number);
printf("Number of tries: %i\n", tries_to_win);
if (tries_to_win < high_score_value)
{
Player_Infos(&player, tries_to_win );
high_score_value = player.player_score;
}
printf("Highest score: %i By: %s\n", player.player_score, player.player_name);
printf("\n");
end_game = Game_Restart();
}
return EXIT_SUCCESS;
}
//Random_Value FUNCTION
int Random_Value(void)
{
srand(time(NULL));
int x = rand();
int y = x % 20;
return y;
}
//Get_User_Choice FUNCTION
int Get_User_Choice(void)
{
int success, x;
char ch;
printf("Your Guess:\t");
success = scanf("%i", &x);
while (success != 1)
{
printf("Your input is not a number. Please try again:\t");
while ((ch = getchar()) != '\n' && ch != EOF);
success = scanf("%i", &x);
}
if (x < 0 || x > 20)
{
printf("Your input must be between 0 and 20. Please try again.\n");
Get_User_Choice();
}
return x;
}
//Check_Result FUNCTION
int Check_Result(int computer, int my_choice)
{
int check_result;
if (my_choice < computer)
{
printf("Computer number is larger!\n");
check_result = FALSE;
}
else if (my_choice > computer)
{
printf("Computer number is smaller!\n");
check_result = FALSE;
}
else if (my_choice == computer)
{
printf("It's a Match! You chose the same number than the computer.\n");
printf("\n");
check_result = TRUE;
}
return check_result;
}
//Try_Again FUNCTION
int Try_Again(int game_result, int computer)
{
int tries_befor_success = 1;
while (game_result != TRUE)
{
int your_number = Get_User_Choice();
game_result = Check_Result(computer, your_number);
tries_befor_success++;
}
return tries_befor_success;
}
//Player_Infos FUNCTION
void Player_Infos(HS_Player *player_p, int score)
{
char new_name[80];
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
scanf("%s", new_name);
printf("\n");
player_p->player_score = score;
player_p->player_name = new_name;
}
//Game_Restart FUNCTION
int Game_Restart(void)
{
int quit_value;
printf("Quit Game ?\n");
printf("Press 'y' to quit or any other keys to continue.\n");
fflush(stdin);
char quit_game = getchar();
printf("\n");
if (quit_game == 'y')
{
quit_value = TRUE;
}
else
{
quit_value = FALSE;
}
return quit_value;
}
The problem is that, in your Player_Infos function, you are assigning the address of a local array to the char* player_name pointer member of the passed structure. When that function ends, the local array it used will be deleted and the pointer in the structure will be invalid. (In the case of the player_score, you don't have that problem, because the given value is copied to the structure member.)
There are several ways around this; one would be to use the strdup() function to make a copy of the local char new_name[80]; array – but that is really overkill, and you would need to manage (i.e. free()) that allocated string whenever you make a modification.
A simpler way is to make the player_name member an actual array of char and then use strcpy() to copy the local array into that member.
Better, still, with the player_name member defined as char [80], you can read directly into that (in the function), and avoid the local array completely:
typedef struct
{
int player_score;
char player_name[80];
} HS_Player;
//...
void Player_Infos(HS_Player *player_p, int score)
{
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
// Read directly. Limit input to 79 chars (allowing room for null terminator).
scanf("%79s", player_p->player_name);
printf("\n");
player_p->player_score = score;
}
Also, just as a "style" tip, you may want to change the member names to just score and name, as the "player" part is implied by the structure type-name itself.
This issue you are having is that you are associating the player name pointer to a variable that goes out of scope when you leave the "player_Infos" function. What you probably would want to do is define the name as a character array in your structure and then use the "strcpy" call in your function instead. Following is a couple of code snippets illustrating that point.
//TYPEDEF STRUCTS
typedef struct
{
int player_score;
char player_name[80];
} HS_Player;
Then, in your function, use the "strcpy" call.
//Player_Infos FUNCTION
void Player_Infos(HS_Player *player_p, int score)
{
char new_name[80];
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
scanf("%s", new_name);
printf("\n");
player_p->player_score = score;
strcpy(player_p->player_name, new_name);
//player_p->player_name = new_name;
}
When I tested that out, I got a name to appear in the terminal output.
Computer number is smaller!
Your Guess: 4
It's a Match! You chose the same number than the computer.
Number of tries: 8
Highest score: 4 By: Craig
FYI, you will need to include the "string.h" file.
Give that a try.
Name Update
The reason your player.player_name is not getting updated is because you can't assign a string this way in C. When doing player_p->player_name = new_name; you're actually saving in player_p->player_name the memory address of new_name.
Instead, what you want to achieve, is to copy each character of new_name to player_p->player_name and in order to achieve this, you have to change the type of prlayer_name field from char* player_name to char player_name[80], then assign it using, for example, strcpy():
#include <string.h>
// [...]
//TYPEDEF STRUCTS
typedef struct
{
unsigned int player_score;
char player_name[80];
} HS_Player;
// [...]
//Player_Infos FUNCTION
void Player_Infos(HS_Player *player_p, int score)
{
char new_name[80];
printf("Congrats! Your made a new high score.\n");
printf("What's your name ?\t");
scanf("%s", new_name);
printf("\n");
player_p->player_score = score;
strcpy(player_p->player_name, new_name);
}
Data Persistence
To make data (players info) persistent over multiple runs, you have to save the content of the struct to a file.
Example
int Save_Score(char* filename, HS_Player* player)
{
FILE* file = fopen(filename, "w");
if (file == NULL)
{
fprintf(stderr, "\nAn error occurred while opening the file\n");
return -1;
}
if (fprintf(file, "%d %s", player->player_score, player->player_name) < 0)
return -1;
fclose(file);
return 0;
}
int Load_Score(char* filename, HS_Player* player)
{
FILE* file = fopen(filename, "r");
if (file == NULL)
{
fprintf(stderr, "\nAn error occurred while opening the file\n");
return -1;
}
if (fscanf(file, "%d %79s", &player->player_score, player->player_name) < 0)
return -1;
fclose(file);
return 0;
}

How do I use the value of a variable in a function else where?

I have a certain program that lets you register members and save their name and birthdate into arrays. The particular function that does this registration uses the following code;
char regmember (struct member a[])
{
int i = 0;
char wow;
do
{
//registration
printf("\n Do you want to add someone else (y/n):");
scanf(" %c",&wow);
i++
}while(wow != 'n');
int nrofmembers = i;
return nrofmembers;
}
-> I save the user input by using
scanf("%s",a[i].name) and scanf("%d",&a[i].ID);
which is why I am using i++. As you realize, the int variable i, will hold the number of members who have been registered. I want to utilize this info in order to use it in loops in other functions, so I went on to save the value of i in another int variable...
int nrofmembers = i;
My problem is, I can't use that variable (nrofmembers) else where, even though I tried returning it, any advice?
you need both to get i in parameter and to return the new value, you can do
int regmember (struct member a[], int i)
{
... use and modify i
return i;
}
or using it as an input-output variable
void regmember (struct member a[], int * i)
{
... use and modify *i
}
In the first case the caller do for instance :
int i = 0;
for (...) {
...
i = regmember(..., i);
...
}
and in the second case :
int i = 0;
for (...) {
...
regmember(..., &i);
...
}
Suppose you keep the members in a global array, then you can manage how many members are in your array also as a global variable, for example
struct member gMembers[MAX_MEMBERS];
int gnMembers;
Your function can now operate on this array directly:
int regmember (void)
{
if (gnMembers < MAX_MEMBERS)
{
// add member
if (scanf("%s",gMembers[gnMembers].name)==1
&& scanf("%d",&gMembers[gnMembers].ID)==1) {
gnMembers++;
return 1; // success
}
}
return 0; // array full or scanf error
}

Changing char[] in C

I looking for a answer and can't find nowhere. I hope you'll help me. I write a simple app which include struct with a name of worker and . But when i want to change value of name i can't do it. I don't know why. Maybe you can't help me or you know another ways to do it? My code:
struct workers {
char name[256]="no";
int pay=-1;
};
void addOne(struct workers work[20]) {
char name[256];
int i=0;
for (i = 0; work[i].name != "no"; i++) {}
printf_s("Enter name of worker: ");
scanf_s("%s", &name);
//-----error here-----
work[i].name = name;
}
int main()
{
int i;
struct workers work[20];
for (i = 0;i < 20; i++) {
if (work[i].name != "no") {
work[i].pay = 100 * i;
}
}
for (i = 0; i < 20; i++) {
printf_s("%s\t%d\n", work[i].name, work[i].pay);
}
return 0;
}
work[i].name = name;
The above line is where the problem is.
Change as below:
snprintf( work[i].name, sizeof(work[i].name), "%s", name);
What you have done is trying to change the base pointer of the array and not the name.
Also there were few more errors in the code, pls resolve them.
It is not possible to set default values to structure as you have done in C.
You have to write code to init each array instance name variable with "no" in a loop and then use one of the string comparison functions to compare the strings. And then call your addOne.

Exit code 11 on extractMin() in PriorityQueue in C'99

I'm new in C programming. I'm developing a priority queue in C'99 with the heap data structure.
I'm using heapifyDown() in combination with swapValues() to sort the heap array for extracting the first element (min-heap) pqueue_extractMin() function. My structure looks like this:
typedef struct ProrityQueue_s PriorityQueue;
typedef struct PriorityQueue_Entry_s *PriorityQueue_Entry;
struct ProrityQueue_s {
int size, last;
char error;
PriorityQueue_Entry *entries;
};
struct PriorityQueue_Entry_s {
char *value;
float priority;
};
For information – Full code for information on gist: https://gist.github.com/it4need/ddf9014bfda9fe6a64bb01a7417422bc
Questions:
Insertion into the Priority queue ("minheap") looks good. Everything is fine. But when I'm extract more than one element at once, I will get this error: "Process finished with exit code 11".
Is this line allowed to copy the whole contents of the last element to the first of the heap? priorityqueue->entries[0] = priorityqueue->entries[priorityqueue->last];
swapValues(priorityqueue, currentPositionIndex, smallestChild); Can I swap values of whole Structure elements? -> implementation (bottom).
HeapifyDown():
void heapifyDown(PriorityQueue *priorityqueue)
{
int currentPositionIndex = 0;
while(currentPositionIndex < priorityqueue->last)
{
int smallestChild = currentPositionIndex;
int leftChildIndex = (2 * currentPositionIndex) + 1;
int rightChildIndex = (2 * currentPositionIndex) + 2;
smallestChild = (priorityqueue->entries[leftChildIndex]->priority < priorityqueue->entries[smallestChild]->priority && priorityqueue->last > leftChildIndex)
? leftChildIndex : smallestChild;
smallestChild = (priorityqueue->entries[rightChildIndex]->priority < priorityqueue->entries[smallestChild]->priority && priorityqueue->last > rightChildIndex)
? rightChildIndex : smallestChild;
if(smallestChild == currentPositionIndex)
{
break;
}
swapValues(priorityqueue, currentPositionIndex, smallestChild); // #todo: Why does this line break the function on two function calls by negative values
currentPositionIndex = smallestChild;
}
}
SwapValues():
void swapValues(PriorityQueue *priorityqueue, int firstIndex, int secondIndex)
{
// #todo: Does this work properly?
PriorityQueue_Entry tmp_entry = priorityqueue->entries[firstIndex];
priorityqueue->entries[firstIndex] = priorityqueue->entries[secondIndex];
priorityqueue->entries[secondIndex] = tmp_entry;
}
extractMin():
char *pqueue_extractMin(PriorityQueue *priorityqueue)
{
if(isEmpty(priorityqueue))
{
priorityqueue->error = ERROR_PRIORITY_QUEUE_EMPTY;
}
priorityqueue->last--;
char *tmp = priorityqueue->entries[0]->value;
priorityqueue->entries[0] = priorityqueue->entries[priorityqueue->last]; // #todo: Is this allowed?
heapifyDown(priorityqueue); // #todo: Why does this line break the extractMin() function on two function calls -> check swapValues() in heapifyDown()
return tmp;
}
Full code for information on gist: https://gist.github.com/it4need/ddf9014bfda9fe6a64bb01a7417422bc

C: how sort and subsort values in a structure

After hours of thinking and tinkering I almost gave up but decided to turn to the community for their help. I'm new to C and I just learned bubble sort. For example the following code sorts by name, what I would like to implement is a sub sort where it also sorts by person ID, how would I do that or change the following code to do just that? (This is structure problem).
struct human {
char name;
char id;
}
function sorting(struct human person)
{
struct human temp
int i, unsorted;
do{
unsorted = 0;
for(i = o; i<count-1; i++)
{
if(strcmp(person[i].name, person.name) > 0)
{
temp = person[i];
person[i] = person[i+1];
person[i+1] = temp;
unsorted = 1;
}
}while(unsorted);
}
First, it would help to break out your comparison function into its own function:
int compare_people(struct human *person1, struct human *person2)
{
return strcmp(person1->name, person2->name);
}
Then, you can more easily change the logic to compare ID if the name is equal:
int compare_people(struct human *person1, struct human *person2)
{
int d = strcmp(person1->name, person2->name);
if (d == 0) {
return person2->id - person1->id;
} else {
return d;
}
}

Resources