I'm trying to take a data from a file and store it in a struct. I use a string called buffer to get all text, and then I use a string called one_line to pass the data to the struct.
I added some explation in the code notes.
#include<stdlib.h>
#include<stdio.h>
#define N 10000
#define line 30
typedef struct player
{
char full_name[N];
int year[N];
char team_name[N];
} player;
void main()
{
char buffer[1000];//string to store all data from afile
char one_line[line];//string for a struct that take each line separate
player p[500];//array of struct
FILE *ptr;//pointer to file
int i=0,count_of_player=0;
ptr=fopen("player of the year.txt","r");
if(ptr==NULL)
{
printf("cant open ");
return;
}
while (fgets(buffer,N,ptr)!=NULL)//the buffer get all the text
{
while (one_line!='\0')//the string get one line in a time
{
fscanf(ptr,"%d %s %s",&(p[i].year),&(p[i].full_name),&(p[i].team_name));\\get date from file to struct
i++;
count_of_player++;
}
}
fclose(ptr);
while (buffer!=NULL)
{
printf("%s",buffer);
}
for (i=0;i<count_of_player;i++)
{
printf("%s won the best player trophy in %d at the team:%s",p[i].full_name,p[i].year,p[i].team_name);
}
}
Related
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;
}
//make a location marker for key items
#include <stdio.h>
#include <string.h>
struct find {int index; char name[50]; char location[50]; };
int main() {
char locate_item[50];
//using struct to add items
struct find item1;
item1.index = 1;
strcpy(item1.name, "guitar");
strcpy(item1.location, "Usually near the table in the living room area.\n");
struct find item2;
item2.index = 2;
strcpy(item2.name, "ipad");
strcpy(item2.location, "Usually on the table or charging on the bed.\n");
//using while and if statements to get user feedback and display the appropriate location
while (locate_item != item1.name || locate_item != item2.name) {
printf("what is the item you want to find? \n");
scanf("%s", locate_item);
printf("You entered %s\n", locate_item);
if (locate_item == item1.name) {
printf("%s", item1.location);
} else if (locate_item == item2.name) {
printf("%s", item2.location);
} else {
printf("Incorrect entry. Please try again.\n");
}
}
return 0;
}
locate_item != item1.name || locate_item != item2.name compares pointer, however, you want to use strcmp() to compare two strings by value. strcmp() returns 0 if the two strings are the same.
In either case, your program doesn't make a lot of sense. You probably want to find locate_item in the an array of items (renamed from find) along these lines:
#include <stdio.h>
#include <string.h>
struct item {
int index;
char name[50];
char location[50];
};
int main() {
struct item items[] = {
{ 1, "guitar", "Usually near the table in the living room area." },
{ 2, "ipad", "Usually on the table or charging on the bed." },
{ 0 }
};
for(;;) {
printf("what is the item you want to find? \n");
char locate_item[50];
scanf("%s", locate_item);
//printf("You entered %s\n", locate_item);
for(int i = 0; items[i].name[0]; i++) {
if(!strcmp(items[i].name, locate_item)) {
printf("%s\n", items[i].location);
goto done;
}
}
printf("Incorrect entry. Please try again.\n");
}
done:
return 0;
}
My issue is when I print out the value of(*user).username outside of the while loop (still in decryptPass) I get the string it was set to, but if I print it inside of the while loop I get whatever string is at the top of the file. I have tried changing it to user->username which didn't work (unsurprisingly). I'm not interested in changing the way the code works but it's essentially just getting every other string of a text file and if the string in the file is the same as the user inputted string it will set the next string to = key.
struct user
{
char username[20];
char encryptedPass[20];
float balance;
};
void decryptPass(struct user *user, struct user userFile[], FILE *encrypKey, FILE *userDetails);
void main()
{
FILE *encrypKey;
FILE *userDetails;
struct user user;
struct user userFile[20];
userDetails = fopen("userDetails.txt", "a+");
encrypKey = fopen("encryptedKey.txt", "a+");
printf("Enter username: ");
scanf("%s", &user.username);
decryptPass(&user, &userFile[20], encrypKey, userDetails);
fclose(userDetails);
fclose(encrypKey);
}
void decryptPass(struct user *user, struct user userFile[], FILE *encrypKey, FILE *userDetails)
{
char buffer[20], key[5];
int i = 0;
while(fgets((userFile[i].username), 20, encrypKey))
{
if(strcmp((*user).username, userFile[i].username) == 0)
{
fgets(key, 20, encrypKey);
}
else
{
fgets(buffer, 20, encrypKey);
}
i++;
}
}
If I strcpy the (*user).username to a local variable of the function then use that instead it works fine. I understand this is a scope issue but I'm just not sure why.
I have been trying to read some strings and integers from a file,but it seems that I don't do it correctly...This programm is supposed to read data from a file...It must create a list with the names of writters.For every writter,it should use a struct like the one I used here...Foe every writter's text,I must also create a struct,like the one I did here..Then,I have to sort the list,create another list with the most popular writers and then print the output...My program is:
#include<stdio.h>
#include<math.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
struct AuthorRecord {
char textTitle[30];
long Download;
struct AuthorRecord *next;
};
typedef struct AuthorRecord *AuthorRecordType;
typedef struct {
char firstName[30];
char lastName[30];
int idNumber,s1;
long s2;
float p;
AuthorRecordType text;
} AuthorType;
struct MemberNodeStruct {
AuthorType *anAuthor;
struct MemberNodeStruct *next;
};
typedef struct MemberNodeStruct *MemberNodeType;
int main()
{
int m,n,i,j,d,z,e,y;
long k;
char s[30];
AuthorType *a;
struct MemberNodeStruct *l,*l2,*temp,*min,*b1,*b2,*r,*r2,*r3;
struct AuthorRecord *t,*t2,*h,*h2,*min2,*temp2;
FILE *f;
f=fopen("project.txt","rt");
if(f==NULL)
exit(-1);
l2=NULL;
t2=NULL;
t=NULL;
fscanf(f,"%d",&n);
getchar();
for(i=1;i<=n;i++)
{
y=0;
a=(AuthorType*)malloc(sizeof( AuthorType));
fgets(s,30,f);
strcpy(a->firstName,s);
fgets(s,30,f);
strcpy(a->lastName,s);
fscanf(f,"%d",&d);
getchar();
a->idNumber=d;
fscanf(f,"%d",&m);
getchar();
t2=NULL;
a->s1=m;
a->s2=0;
for(j=1;j<=m;j++)
{
t=(struct AuthorRecord*)malloc(sizeof(struct AuthorRecord));
fgets(s,30,f);
e=0;
h=t2;
while(e==0 && h!=NULL)
{
if(strcmp(h->textTitle,s)==0)
{
e=1;
h2=h;
}
else
h=h->next;
}
if(e==0)
{
strcpy( t->textTitle,s);
fscanf(f,"%ld",&k);
getchar();
t->Download=k;
a->s2=a->s2+t->Download;
t->next=t2;
t2=t;
}
else
{
y=y+1;
fscanf(f,"%ld",&k);
getchar();
h2->Download=h2->Download+k;
a->s2=a->s2+k;
}
}
a->s1=a->s1-y;
a->p=round(a->s2/a->s1);
a->text=t2;
l=(struct MemberNodeStruct*)malloc(sizeof(struct MemberNodeStruct));
l->anAuthor=a;
l->next=l2;
l2=l;
}
........ (150 more lines of code)
.....
system("pause")
return(0);
I have tried this program with scanf and gets instead of a file and fscanf and fgets and it worked correctly...That's the reason I don't write the rest of my code.
project.txt is:
5
Julius Caesar 101
2
DeBelloGallico
3000
DeBelloCivili
8000
Sun Tzu 544
3
TheArtOfWar
5000
TheArtOfWar
5000
Strategems
3000
Plato Athenian 427
4
TrialOfSocrates
10000
Symposium
15000
TheRepublic
7000
Apology
9000
Gaius Suetonius 69
3
thetwelvecaesars
7000
dePoetis
500
DeClarisRhetorebus
1000
Orestis Mastakas 1995
1
WhyDidRomePrevail
15
Whenever I run this program,it ends up in a failure...For some reason,it demands input from me...I tried to remove the getchar() but still, it didn't work! What should I do?
It reads input from stdin, because you told it to do that :
fscanf(f,"%d",&n);
getchar();
Try making sure, you don't have anything reading input from default (file descriptor 0).
If you need to read 1 char from f, then use fgetc instead of getchar.
I have a file which is opened for both write/read (fopen(name,"wb+")) which contains a load of the struct below
struct pedia
{
int code;
char descr[50];
int TM;
int pos;
int flag;
};
The whole file is initialized with codes from 0 to the size of the file (user gives the size)flags equal to 0 ,descr=" " and TM=pos=-1
When i ask the user to write the # of the registration he wants to update and i print the struct which is saved there it s printed correctly.
Also when i call the input function in which the user sets new values for every variable in the struct i print the code,descr etc. right after and they are changed successfully .
However when i use fwrite to write the struct to the file it only writes 1 item successfully in the file.
void fileupdate(FILE *f,int filesize)
{
struct pedia *field;
field=(struct pedia *)malloc(sizeof(struct pedia));
int k,key;
char opt[5];
int num=0;
while(1)
{
puts("\nUPDATE\n");
printf("\nType the # of the registration you want to update (key must be between 0 and %d) \n\nkey:",filesize);
scanf("%d",&key);
getchar();
if(key>=0 && key<=filesize)
{
fseek(f,sizeof(struct pedia)*key,SEEK_SET);
fread(field,sizeof(struct pedia),1,f);
printf("%d,%s,%d,%d,%d\n",field->code,field->descr,field->TM,field->pos,field->flag);
if(field->flag==0)
{
puts("type yes to register new info or no to cancel the update\n");
fgets(opt,sizeof(char)*5,stdin);
if(isspace(*(opt+strlen(opt)-1)))
*(opt+strlen(opt)-1)='\0';
if(strcmp(opt,"yes"))
continue;
printmask();
input(&field);
num=fwrite(field,sizeof(struct pedia),1,f);
printf("\n%d,%s,%d,%d,%d\n",field->code,field->descr,field->TM,field->pos,field->flag);
printf("num=%d\n",num);
}
}
}
There is no fseek() between fread() and fwrite(), so fwrite() doesn't overwrite the struct you wanted to update but the next one.