Structure pointer declared in function - c

Here is the part of the code that isnt working for me.I am declaring a pointer to a structure and I try to use it on a function,although c says that it cant convert main person to person.
void display (char *s2,FILE *f1,int max);
void insert (FILE *f1, struct person *p1);
void deletestring (FILE *f1,FILE *f2,char *s2,char *s1,char *file1,char *file2,int max);
void edit (FILE *f1,FILE *f2,char *s2,char *s1,char *file1,char *file2,struct person *p1,int max);
int main ()
{
char s1[MAX],s2[MAX];
FILE *f2,*f1;
struct person
{
char id[MIN];
char emer[MIN];
char mbiemer[MIN];
};
struct person p1;
struct person *pp1;
pp1 = &p1;
char *file1 = "f1.txt";
char *file2 = "f2.txt";
int zgjedhja=1;
printf("Programi funksionon sipas shpjegimit \n :");
printf("Shtypni 1 per te shtuar nje person \n Shtypni 2 per te ndryshuar informacionin e nje personi \n Shtypni 3 per te shfaqur te dhenat \n Shtypni 4 per te fshire nje person \n Shtypni -1 per te dale nga programi \n ");
while (zgjedhja != -1 )
{
printf("Jepni zgjedhjen tuaj \n ");
scanf(" %d " , & zgjedhja );
switch (zgjedhja)
{
case 1:
f1=fopen(file1,"a");
insert (f1,pp1);

The type struct person has main scope, so it won't have the same meaning in insert. In fact, a structure type whose members have not been specified is known as an incomplete type. To remove this error, declare your structure outside of your function.
struct person
{
/* ... */
};
/* Function declarations. */
int main (void)
{
/* ... */
}

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;
}

Having problems displaying structure array content

I want to display structure members based on user input, but I don't know if I've stored the input properly.
When I try display all people, it just outputs random numbers.
These are the structures and function prototypes
#define MAX_NAME_LEN 15
#define MAX_NUM_PERSON 4
#define MAX_JOB_LENGTH 20
typedef struct birth_date
{
int month;
int day;
int year;
} person_birth_t;
typedef struct person
{
char pName[MAX_NAME_LEN];
char job[MAX_JOB_LENGTH];
person_birth_t birth_t;
} person_t[MAX_NUM_PERSON];
void print_menu (void);
void scanPerson(person_t p, int);
void displayPeople(person_t p);
This is the main code for the program, a menu is printed asking user to input a number, if a user enters 1 then it prompts them to add a person. Entering 2 displays all people entered.
int main(void)
{
/* TODO */
print_menu();
return 0;
}
void print_menu (void)
{
int choice;
person_t p;
static int index = 0;
int *indexP = NULL;
indexP = &index;
/*Print the menu*/
scanf("%d", &choice);
switch (choice)
{
case 1:
if (index < MAX_NUM_PERSON){
scanPerson(p, index);
++*indexP;
print_menu();
} else {
printf("Can't add more people - memory full \n");
print_menu();
}
break;
case 2:
displayPeople(p);
break;
case 3:
exit(0);
break;
default:
print_menu();
}
}
/*function called when add person is chosen from menu */
void scanFlight(person_t p, int index){
/*printf to enter name*/
scanf(" %s", p[index].pName);
/*printf to enter job*/
scanf("%s", p[index].job);
}
void displayPeople(person_t p){
for(int i = 0; i < MAX_NUM_PERSON; i++){
printf("%s %d-%d-%d %s \n",p[i].pName
,p[i].birth_t.month
,p[i].birth_t.day
,p[i].birth_t.year
,p[i].job);
}
}
I've tried other ways to take input and add it to a struct array, but I'm just not sure how to do it right.
person_t p;
Here, you use the local variable p (in print_menu function), so each recursion, you just print the parameters of the local variable that is not initialized.
To solve it, you can declare p as the global variable.
OT, in scanFlight function, to avoid overflow, you should change the scanf function to:
/*printf to enter name*/
scanf("%14s", p[index].pName);
/*printf to enter job*/
scanf("%20s", p[index].job);
And, rename scanPerson to scanFlight, because i do not see any implementation of scanPerson function in your code. I think it's typo, no ?
None of the methods were working, so instead of trying to figure it out, I scrapped the static index and indexP.
Instead, I initialized p with malloc:
person_t *p= malloc(MAX_NUM_PERSON * sizeof(person_t));
I changed the scan function to accommodate for the change and made index a pointer instead, and I made the display function pass the index.
When I ran it, the output was correct.

Populate Arrays of Structures from a File

I have a .dat file filled with ints and doubles that I need to populate an array of structures with, and I'm having issues figuring out the syntax.
Here is the file:
9383 8.86
2777 69.15
7793 83.35
5386 4.92
6649 14.21
2362 0.27
8690 0.59
7763 39.26
540 34.26
9172 57.36
5211 53.68
2567 64.29
5782 15.30
2862 51.23
4067 31.35
3929 98.02
4022 30.58
3069 81.67
1393 84.56
5011 80.42
6229 73.73
4421 49.19
3784 85.37
5198 43.24
8315 43.70
6413 35.26
6091 89.80
9956 18.73
6862 91.70
6996 72.81
Here is my code:
typedef struct student
{
double score;
int id;
char grades;
} Student;
int getScores(FILE *input, Student class);
void main(void)
{
char filename[] = "scores.dat";
FILE *input;
Student class[MAXNUM];
int numScores;
double average;
input = fopen("scores.dat", "r");
if (input == NULL)
{
printf("EOF");
exit(1);
}
}
int getScores(FILE *input, Student class)
{
double s;
int i, count = 0;
while(fscanf(input, "%d %lf", &i, &s) == 2)
{
class[count].score = s;
class[count].id = i;
count++;
}
My main issue lies in the while loop where I am trying to populate the array with the int and doubles of the scores.dat file.
I get the following error when I compile:
lab5.c:53:8: error: subscripted value is neither array nor pointer nor
vector
class[count].score = s;
^
lab5.c:54:8: error: subscripted value is neither array nor pointer nor
vector
class[count].id
Thank you for any help or tips.
Just change function getScores definition and declaration argument class from
`int getScores(FILE *input, Student class);`
to
`int getScores(FILE *input, Student *class);`

having problems running my c program that has two structs and enumeration constants

the question says have two structs
first struct should have these members( string called title with length of 15 characters, double called length, genre of type enum genres with one of these genres as a enumeration constant Blues , HipHop, Jazz, Country, Electronic, Rock, Other).
second struct should have(string called title with length of 20 characters, string called artist with length of 30 characters, member called song of type Song that contains the maximum of 4 songs, and last member a integer var called c that is used as a counter of number of songs.)
struct song must be aliased to Song.
struct album must be aliased to Album.
my program is like this
enum genres { Blues = 0, HipHop, Jazz, Country, Electronic, Rock, Other};
struct song {
char title[15];
double length;
enum genres genre;
};
typedef struct song Song;
struct album {
char title[20];
char artist[30];
Song songs[4];
int noOfSongs;
};
typedef struct album Album;
Now from here i am having problems because the question says.
Have:
getAlbum function, that has Album pointer as a parameter that prompts user for title of album and name of artist.
getSong function that has Album pointer as a parameter that prompts user for song title and length of song and genre of that song.
printAlbum function this function display the information prompted by the user.
NOTE that number songs in an album have a maximum of 4.
I have came up with these function prototypes
void getAlbum( Album *aPtr);
void getSong( Album *sPtr);
void printAlbum( Album *pPtr);
I am having problems with functions and implementing and also i am not sure about my enum and struct album if it is correct cause i can't access neither of them.
Implementing a function is actually rather simple. You already got the protoype, so you'll only have to add brackets to have a basic function:
void getAlbum(Album *aPtr) {
}
Of course, this won't do anything yet, so let's start with a simple prompt:
void getAlbum(Album *aPtr) {
printf("Enter the album name: ");
}
This will now display the text, but it won't ask for the actual text. To do this there are again several different approaches. I'll be using scanf() here, although that one should only be used for testing purposes and (possibly) internal tools, because it can be rather tricky and error prone to use (e.g. if garbage is entered).
void getAlbum(Album *aPtr) {
printf("Enter the album name: ");
scanf("%19s", aPtr->title); // read up to 19 characters as a (s)tring; the 20th will be the terminator ('\0')
}
There you go. Just expand this to read all the values required. Same for the getSong() function.
Printing everything will then be rather similar, just passing the members as the parameters of a printf() rather than scanf().
Since the compiler always pads a type to a multiple of 4 bytes (char = 1 byte), your buffers could use that space without any extra cost. And you need it for the terminating '\0' character anyways. What about shortening the definitions, btw?
typedef enum { Blues, HipHop, Jazz, Country, Electronic, Rock, Other} Genre;
typedef struct {
char title[16];
double length;
Genre genre;
}
Song;
typedef struct {
char title[21];
char artist[31];
Song songs[4];
int noOfSongs;
}
Album;
You may of course write typedef struct album { ... } Album; if you need the name struct album too, but I don't see any reason for this in your case. Here are the functions:
void getAlbum(Album *aPtr) {
printf("Album: ");
scanf("%20s", aPtr->title);
printf("Artist: ");
scanf("%30s", aPtr->artist);
int no = -1;
while(no < 0 || no > 4) {
printf("Tracks: ");
scanf("%d", no);
}
aPtr->noOfSongs = no;
for(int i = 0; i < no; ++i) getSong(&aPtr->songs + i);
}
void getSong(Song *sPtr) {
printf("Song: ");
scanf("%15s", sPtr->title);
double len = -1;
while(len < 0 || len > 100) {
printf("Length: ");
scanf("%f", len);
}
char genre[16];
int genreNo = -1;
while(genreNo == -1) {
printf("Genre: ");
scanf("%15s", genre);
if(strcmp(genre, "Blues") == 0) genreNo = 0;
else if(strcmp(genre, "Hip Hop") == 0) genreNo = 1;
...
else genreNo = 6;
}
sPtr->genre = (Genre)genreNo;
}
void printAlbum(Album *aPtr) {
printf("Album: %s\nArtist: %s\n", aPtr->title, aPtr->artist);
for(int i = 0; i < aPtr->noOfSongs; ++i) printSong(&aPtr->songs + i);
}
void printSong(Song *sPtr) {
printf("\tSong: %s\n\tLength: %.2f\n\tGenre: ", sPtr->title, sPtr->length);
switch(sPtr->genre) {
case Blues: printf("Blues\n"); break;
case HipHop: printf("Hip Hop\n"); break;
...
default: printf("Other\n"); break;
}
}

C CSV GLIB sort optmization

I was asked a question on a recent interview at Sevone but I never got a response on how I did. I only had 2 hours to complete the challenge and i could not get it to sort by gender. Here is what I started with, and even further below was my solution
// Sevone Programming Challenge!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
//! This is the sex of a human.
typedef enum { MALE, FEMALE } Gender;
//! This is a human person.
typedef struct Person {
//! The given name.
char* firstName;
//! The family name.
char* lastName;
//! The age, in calendar years.
int age;
//! The sex (see above).
Gender gender;
} Person;
/** This is the bonus function.
**/
void bonusFunction();
/** This is the core of the program.
**/
int main( int argc, char** argv ) {
// INSTRUCTIONS:
// Please refer to: http://developer.gnome.org/glib/2.30/glib-Double-ended-Queues.html
// 1. Open "people.csv".
// 2. Read in the list of people (format is "firstName lastName,age,{male|female}").
// 3. Create a "Person" for each one read.
// 4. Insert each "Person" into a GLib GQueue (this is a "double-ended queue", but think of it like a list).
// 5. Sort the list (by using "g_queue_sort") by:
// 1. Gender
// 2. Last name
// 6. Print out the list (by using "g_queue_foreach"). The format should be:
// (male/female) Last name, First name (age)
// 7. Free up all memory (we're gonna valgrind this afterward).
// Ready for the bonus?
bonusFunction();
// KTHXBYE
return( 0 );
}
/** This is the bonus function.
**/
void bonusFunction() {
//! This is the bonus array!
int arrayOfInts[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
// BONUS!
// 1. Loop through the bonus array and print it without using square brackets ("[" and "]").
// All done.
return;
}
Here is my solution, please let me know how to sort by gender or any other optimizations.
// Programming Challenge!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
//! This is the sex of a human.
typedef enum { MALE, FEMALE } Gender;
//! This is a human person.
typedef struct Person {
//! The given name.
char* firstName;
//! The family name.
char* lastName;
//! The age, in calendar years.
int age;
//! The sex (see above).
Gender gender;
} Person;
/** This is the bonus function.
**/
void bonusFunction();
gint sort_lastName(gconstpointer a, gconstpointer b, gpointer data) {
return strcmp( ((Person*)a)->lastName, ((Person*)b)->lastName );
}
void prt(gpointer per) {
printf("%s, %s %d \n ", ((Person*)per)->lastName, ((Person*)per)->firstName,((Person*)per)->age);
}
/** This is the core of the program.
**/
int main( int argc, char** argv ) {
puts("Starting SevOne Test\n");
// INSTRUCTIONS:
// Please refer to: http://developer.gnome.org/glib/2.30/glib-Double-ended-Queues.html
// 1. Open "people.csv".
// 2. Read in the list of people (format is "firstName lastName,age,{male|female}").
// 3. Create a "Person" for each one read.
// 4. Insert each "Person" into a GLib GQueue (this is a "double-ended queue", but think of it like a list).
// 5. Sort the list (by using "g_queue_sort") by:
// 1. Gender
// 2. Last name
// 6. Print out the list (by using "g_queue_foreach"). The format should be:
// (male/female) Last name, First name (age)
// 7. Free up all memory (we're gonna valgrind this afterward).
char buffer[100];
int counter=0;
char * token;
GQueue* q = g_queue_new();
FILE *fp;
fp=fopen("people.csv", "r");
if( fp == NULL )
{
puts("Failed to open file");
return 0;
}
while(fgets(buffer, sizeof(buffer), fp) != NULL)
{
Person *ptr_one;
ptr_one = (Person *) malloc (sizeof(Person));
// Get first name
token = strtok(buffer," ");
ptr_one->firstName=(char *)malloc(sizeof(char)*sizeof(token));
strcpy(ptr_one->firstName,token);
// Get last name
token = strtok(NULL,",");
ptr_one->lastName=(char *)malloc(sizeof(char)*sizeof(token));
strcpy(ptr_one->lastName,token);
// Get age
token = strtok(NULL, ",");
ptr_one->age=(int *)malloc(sizeof(int));
sscanf (token, "%d", &ptr_one->age);
// Get gender
token = strtok(NULL,",\n");
g_queue_push_tail(q, ptr_one);
}
// Sort list by last name
g_queue_sort(q, (GCompareDataFunc)sort_lastName, NULL);
// print the list
g_queue_foreach(q, (GFunc)prt, NULL);
if( fclose(fp) != 0 )
{
puts("Failed to close file."); /* prints !!!Hello World!!! */
return 0;
}
g_queue_free(q);
// Ready for the bonus?
bonusFunction();
// KTHXBYE
return( 0 );
}
/** This is the bonus function.
**/
void bonusFunction() {
//! This is the bonus array!
int arrayOfInts[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
// BONUS!
// 1. Loop through the bonus array and print it without using square brackets ("[" and "]").
// All done.
return;
}
And the CSV below
Brad Fawcett,24,male
Steve Settlemyre,29,male
Dave Hegenbarth,44,male
Cathy Colapiertro,41,female
Steve Mahoney,23,male
Dave Mulford,26,male
Doug Manley,24,male
Steve Carrington,24,male
Lauren Jordan,31,female
Tanya Bakalov,26,female
First you need to parse the gender properly :
// Get gendor
token = strtok(NULL,",\n");
if(strcasecmp(token, "female") == 0)
ptr_one->gender = FEMALE;
else
ptr_one->gender = MALE;
Then use an appropriate comparison function :
gint sort_gender(gconstpointer a, gconstpointer b, gpointer data) {
return ((Person*)a)->gender - ((Person*)b)->gender;
}
And the bonus function :
void bonusFunction() {
//! This is the bonus array!
int arrayOfInts[] = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
// BONUS!
// 1. Loop through the bonus array and print it without using square brackets ("[" and "]").
int i;
int *n = arrayOfInts;
for(i = 0; i < sizeof(arrayOfInts)/sizeof(int); i++)
printf("%d\n", *n++);
return;
}

Resources