I have created the code below. What i need to do is that I need to get and input from the user(username and password) and I need to check with a file what I entered. The Problem forces me not to copy the whole .txt file in once. The .txt file is converted like this:
root
jfl34jgf
ben
12b43
stella
ldfo421
kate
jfd45g
bill
iu3556
guest
1234
test
1234
So I was thinking of getting all the user names, putting them into a list and then checking each one of them with the input. I created a struct that includes the username name, the position at which username name ends (using ftell()) and the next pointer that points to the next element. As you can see the text is formatted in the way that one like is username and the other is the password. so the password comes right after the username. using ftell() for each username if the comparison of name gives me true than I can check for the password check.
This is my code until now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct names
{
char name[20];
int pos;
struct names *next;
};
typedef struct names Names;
void create_list(Names *l, char *temp1, int pos)
{
Names *temp;
temp=(Names*)malloc(1*sizeof(Names));
temp->next=NULL;
strcpy(temp->name, temp1);
temp->pos=pos;
temp->next=l;
printf("%s ", temp->name);
l=temp;
printf("%s\n", l->name);
}
void create_list_from_File(FILE *fp, Names *l)
{
char ch;
int i=0, check=0, pos;
char temp1[20];
temp1[0]='\0';
while(1)
{
if(check==1)
break;
while((ch=fgetc(fp))!='\n')
{
temp1[i]=ch;
i++;
}
temp1[i]='\0';
pos=ftell(fp)+1;
create_list(l,temp1, pos);
while((ch=fgetc(fp))!='\n')
{
if(ch==EOF)
{
printf("EOF ");
check=1;
break;
}
}
i=0;
}
}
void display(Names *l)
{
Names *cursor;
cursor=l;
while (cursor!=NULL)
{
printf("%s\n", cursor->name);
cursor=cursor->next;
}
}
int main()
{
char usern[20][20];
char passw[20];
FILE *fp;
Names l;
l.next=NULL;
char c;
int i=0;
fp=fopen("users.txt", "r");
if(fp==NULL)
{
printf("File not opened!\n");
exit(1);
}
create_list_from_File(fp, &l);
display(&l);
/* fgets(usern, 20, stdin);
usern[strlen(usern)-1]='\0';
while(strcmp(usern, "exit")!=0)
{
fgets(passw,20, stdin);
passw[strlen(passw)-1]='\0';
check(fp, usern, passw);
}
*/
return 0;
}
Right now the I do not see stuff inside the linked list. I am getting the strings from the file correctly ( the username are printed) but when I try to print the list it just gives me some weird values. Help would be much appreciated.
The provided source code presents a classical error when managing linked-list. Modifying the content of a pointer inside a function when passed as value as only a local effect and doesn't affect the value in the calling function.
Problem - Modifying the value of Names *l in the function create_list().
The function create_list() adds a new node Names *temp; in front of the list to increase performance by modifying only the first node.
The new node is pointing to the first temp->next=l;,
Then the new node becomes the first l=temp;.
When printing locally values, seems no problem.
But, the assignment l=temp; is only available inside the function (assignment to a local Names *l pointer) and when return to the calling function create_list_from_File() the l doesn't change.
Solution 1 - Modify the value of the l->next is the fastest solution.
In the main(), a starting Names l; has been declared with an assignment l.next=NULL; meaning (list empty).
In the create_list() function, the assignment is:
strcpy(temp->name, temp1);
temp->pos=pos;
// assigning to the next pointer
temp->next=l->next;
printf("%s ", temp->name);
// modify the next pointer
l->next=temp;
printf("%s\n", l->next->name);
Instead of:
strcpy(temp->name, temp1);
temp->pos=pos;
temp->next=l;
printf("%s ", temp->name);
l=temp;
printf("%s\n", l->name);
To be complete, for that shortest solution, the function display() shall start from the l->next which is the first node.
void display(Names *l)
{
Names *cursor;
cursor=l->next;
while (cursor!=NULL)
{
printf("%s\n", cursor->name);
cursor=cursor->next;
}
}
Thank you #J.Piquard for the help given above. I managed to solve this problem. I am posting the code below and the code can be tested in the above .txt file. Firstly an user enters the input and after that the username followed by a password. It is assumed that the username input will be always correct, but to check username is not that hard.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct names
{
char name[20];
int pos;
struct names *next;
};
typedef struct names Names;
Names *create_list(Names *l, char *temp1, int pos)
{
Names *temp;
temp=(Names*)malloc(1*sizeof(Names));
strcpy(temp->name, temp1);
temp->pos=pos;
temp->next=l;
return temp;
}
Names * create_list_from_File(FILE *fp)
{
char ch;
int i=0, check=0, pos;
Names *l=NULL;
char temp1[20];
temp1[0]='\0';
while(1)
{
if(check==1)
break;
while((ch=fgetc(fp))!='\n')
{
temp1[i]=ch;
i++;
}
temp1[i]='\0';
pos=ftell(fp)+1;
l=create_list(l,temp1, pos);
while((ch=fgetc(fp))!='\n')
{
if(ch==EOF)
{
check=1;
break;
}
}
i=0;
}
return l;
}
int check_usrn(char *s, Names *l, int *i)
{
int flag=0;
Names *cursor=l;
*i=0;
while (cursor!=NULL)
{
if(strcmp(cursor->name, s)==0)
{
flag=1;
break;
}
cursor=cursor->next;
(*i)++;
}
return flag;
}
int check_passw(FILE *fp, Names *l, char *passw, int *i)
{
Names * cursor;
cursor=l;
int m=0, flag=0;
char c, temp[20];
while(m!=*i)
{
cursor=cursor->next;
m++;
}
m=0;
fseek(fp, cursor->pos-1, SEEK_SET);
while((c=fgetc(fp))!='\n')
{
if(c==EOF)
break;
temp[m]=c;
m++;
}
temp[m]='\0';
if(strcmp(passw, temp)==0)
flag=1;
return flag;
}
int main()
{
char usern[20];
char passw[20];
char file_name[20];
FILE *fp;
Names *l=NULL;
int i=0;
fgets(file_name, 20, stdin);
file_name[strlen(file_name)-1]='\0';
fp=fopen(file_name, "r");
if(fp==NULL)
{
printf("File not opened!\n");
exit(1);
}
l=create_list_from_File(fp);
while(strcmp(usern, "exit")!=0)
{
fgets(usern, 20, stdin);
usern[strlen(usern)-1]='\0';
if(check_usrn(usern, l, &i)==1)
{
fgets(passw, 20, stdin);
passw[strlen(passw)-1]='\0';
if(check_passw(fp ,l, passw, &i)==1)
printf("Access to user %s is granted.\n", usern);
else
printf("Access to user %s is denied.\n", usern);
}
}
printf("Exiting ...\n");
fclose(fp);
return 0;
}
Related
The problem that I have is that, once I want to read the file, the program prints out everything, but it doesn't read the last element of the file.
So in the file lets say I have:
admin:pass:1000:off
test:testxx:1000:off
ret:passx:1000:off
It prints out the first 2 lines and then it says "End of the buffer" (its just a printf that I put into the code in order to understand where is the problem).
After printing out "End of the buffer" it prints out the last line..
What am I doing wrong?
#include <stdlib.h> /* exit */
#include <errno.h> /* perror */
#include <stdio.h>
#include <unistd.h> /* write, read, close*/
#include <sys/types.h>
#include <sys/stat.h> /*open */
#include <fcntl.h>
#include <string.h>
#define MAX 500
struct utente{
char username[MAX];
char password[MAX];
int gettoni;
char stato[MAX];
struct utente *next;
};
void menu(int);
struct utente* lettura_file(struct utente *);
struct utente* ins_coda(struct utente *t, char username[], char password[], char gettoni[], char stato[]);
void stampa_lista(struct utente*);
struct utente* elabora(struct utente *top, char buffer[]);
int check(struct utente *, char *);
void aggiornamento_file(struct utente *top);
int main(){
while(1){
char scelta[MAX], stringa[MAX];
int i=0, res=0;
struct utente *TOP=NULL;
printf("1. STAMPA LISTA\nInserisci scelta --> ");
scanf("%s", scelta);
i=atoi(scelta);
switch(i){
case 1:
TOP=lettura_file(TOP);
stampa_lista(TOP);
/*printf("Inserisci stringa da trovare: ");
scanf("%s", stringa);
res=check(TOP, stringa);
if(res==1)
aggiornamento_file(TOP);
*/
break;
}
}
return 0;
}
struct utente* lettura_file(struct utente *top){
int fd, nread;
char buffer[MAX];
fd=open("utenti.txt", O_RDONLY);
if(fd==-1){
perror("ERRORE APERTURA FILE");
return top;
}
while((nread=read(fd, buffer, MAX)>0)){
top=elabora(top,buffer);
}
close(fd);
return top;
}
struct utente* elabora(struct utente *top, char buffer[]){
char username[MAX], password[MAX], gettoni[MAX], stato[MAX];
int i=0;
int j=0; //indice username
int k=0; //indice password
int t=0; //indice gettoni
int x=0; //indice stato
int count=0;
printf("Inzio buffer:\n%sfine buffer\n" ,buffer);
while(buffer[i]!='\0'){
//ELABORO NOME
while(buffer[i]!=':'){
username[j]=buffer[i];
j++;
i++;
}
username[j]='\0';
i++;
//ELABORO COGNOME
while(buffer[i]!=':'){
password[k]=buffer[i];
k++;
i++;
}
password[k]='\0';
i++;
//ELABORO GETTONI
while(buffer[i]!=':'){
gettoni[t]=buffer[i];
t++;
i++;
}
gettoni[t]='\0';
i++;
while(buffer[i]!='\n' && buffer[i]!='\0'){
stato[x]=buffer[i];
x++;
i++;
}
stato[x]='\0';
if(buffer[i]=='\n')
i++;
if(buffer[i]=='\0'){
printf("\nEnd of the buffer %c\n", buffer[i]);
printf("Fine%s %s %s %s\n\n", username, password, gettoni, stato);
top=ins_coda(top, username, password, gettoni, stato);
return top;
}
printf("Utente %d, %s %s %s %s\n\n", count, username, password, gettoni, stato);
top=ins_coda(top, username, password, gettoni, stato);
bzero(username, MAX);
bzero(password, MAX);
bzero(gettoni, MAX);
bzero(stato, MAX);
j=0;
k=0;
t=0;
x=0;
}
return top;
}
struct utente* ins_coda(struct utente *t, char username[], char password[], char gettoni[], char stato[]){
struct utente *p, *top;
int n_gettoni;
p=(struct utente*)malloc(sizeof(struct utente));
strcpy(p->username, username);
strcpy(p->password, password);
n_gettoni=atoi(gettoni);
p->gettoni=n_gettoni;
strcpy(p->stato, stato);
p->next=NULL;
if(t==NULL)
return p;
top=t;
while(t->next!=NULL)
t=t->next;
t->next=p;
return top;
}
void stampa_lista(struct utente *TOP){
int i=1;
while(TOP!=NULL){
printf("Utente %d:\n Username: %s\nPassword: %s\nGEttoni: %d\nStato: %s\n", i, TOP->username, TOP->password, TOP->gettoni, TOP->stato);
TOP=TOP->next;
i++;
}
return;
}
int check(struct utente *top, char stringa[]){
int len=strlen(stringa);
while(top!=NULL){
if(strncmp(top->username, stringa, len)==0){
strcpy(top->stato, "on");
printf("OK\n");
return 1;
}else{
printf("KO\n");
return 0;
}
top=top->next;
}
return 0;
}
void aggiornamento_file(struct utente *top){
char username[MAX], password[MAX], gettoni[MAX], stato[MAX]="";
int fd;
fd = open("utenti.txt", O_WRONLY |O_TRUNC, S_IRUSR | S_IWUSR);
if(fd==-1){
perror("ERROR apertura file utenti!");
exit(1);
}else{
while(top!=NULL){
strcpy(username, top->username);
strcpy(password, top->password);
sprintf(gettoni, "%d", top->gettoni);
strcpy(stato, top->stato);
write(fd, username, strlen(username));
write(fd, ":", 1);
write(fd, password, strlen(password));
write(fd, ":", 1);
write(fd, gettoni, strlen(gettoni));
write(fd, ":", 1);
write(fd, stato, strlen(stato));
write(fd, "\n", 1);
top=top->next;
}
}
close(fd);
return;
}
Unless your file contains binary data and you actually put a 0x00 at the end of it, it shouldn't contain any zeros for the buffer[i] != '\0' check.
C strings are NULL terminated, but it's not usual to include this terminating zero when writing to text files. Text file editors don't do that either.
One problem is that you are not initializing the buffer variable.
Probably you are getting zeros by chance when the program allocates the 500 bytes for it.
One way you can initialize a buffer with zeros is by setting it's first element to zero at the declaration:
char buffer[MAX] = {0,};
Now, if I understood correctly your doubt, I don't see that the end of the file is happening before the program reads the last entry. What is happening there is that the program is printing the message with the last line after it prints the message of the end of the file. But the program did read the last line before the end of the file and stored it in the variables used by printf.
Confusion typically arises in codes with big functions. elabora function is big, complicated and hard to debug. You can make it simpler if you break it in smaller functions. I believe it gets much better if it reads lines instead of the whole file. I rewrote it quickly as an example:
void get_field(char **src, char dst[MAX])
{
int j = 0;
while (*(*src) && *(*src) != ':' && *(*src) != '\n') {
dst[j++] = *(*src);
(*src)++;
}
}
struct utente* elabora(struct utente *top, char *line, ssize_t line_len, int *count)
{
char username[MAX] = {0,};
char password[MAX] = {0,};
char gettoni[MAX] = {0,};
char stato[MAX] = {0,};
get_field(&line, username);
get_field(&line, password);
get_field(&line, gettoni);
get_field(&line, stato);
printf("Utente %d, %s %s %s %s\n\n", ++(*count), username, password, gettoni, stato);
top = ins_coda(top, username, password, gettoni, stato);
return top;
}
It can now be called from a function that reads the file by lines using geline function:
struct utente* lettura_file(struct utente *top)
{
FILE *file = NULL;
char *buffer = NULL;
size_t buffer_size = 0;
int count = 0;
ssize_t n_read = 0;
if ((file = fopen("utenti.txt", "r")) == NULL) {
perror("ERRORE APERTURA FILE");
return top;
}
while ((n_read = getline(&buffer, &buffer_size, file)) > 0) {
top = elabora(top, buffer, n_read, &count);
}
if (buffer != NULL)
free(buffer);
if (file != NULL)
fclose(file);
return top;
}
These functions are still not safe, but I believe they have better readability and tend to be easier do debug. strtok would be better than parsing tokens this way. Using other functions for opening and reading the file, as suggested by the questions' comments, would also improve the code.
Let's call this file f1.txt and it has given attributes.
Student code
name
ID
and resident structure from another file let's call f2.txt will be read with the following attributes
ID
City
and residence will be asked from keyboard.
I tried to but gett stucked at some point
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
int student_code;
char name[20];
char ID[20];
};
int main()
{
FILE *input_file;
struct student input;
input_file = fopen("f1.txt", "r");
if(input_file == NULL)
{
fprintf(stderr, "\nError!\n");
exit(1);
}
while(fread(&input, sizeof(struct student), 1, input_file))
printf("student code = %d name = %s ID = %s", input.student_code,
input.name, input.ID);
fclose(input_file);
return 0;
}
I'm new at C programming
for example f1.txt file will be in the following format
f1.txt
123456 yourname 987654
564566 test 454545
Use fscanf to read the lines because you know the format
Store the values into temporary variables
Copy them into a proper data structure: if you don't know the number of students use a dynamic array or a list.
EDIT:
Arrays allow random access, on the other hand lists only allow sequential access.
Here's my attempt using lists:
typedef struct student
{
int student_code;
char name[20];
char ID[20];
struct student* next;
}student_t;
typedef struct list_s
{
int size;
student_t* head;
student_t* tail;
} list_t;
void list_push_back(list_t* l, int code, char n[20], char id[20])
{
student_t* tmp = (student_t*)calloc(1,sizeof(*tmp));
tmp->student_code = code;
strncpy(tmp->name, n, 20);
strncpy(tmp->ID, id, 20);
if (l->head == NULL)
{
l->head = tmp;
l->tail = tmp;
l->size++;
return;
}
l->tail->next = tmp;
l->size++;
}
void list_print(list_t* l)
{
student_t* it = l->head;
while (it)
{
fprintf(stdout, "%d %s %s\n", it->student_code, it->name, it->ID);
it = it->next;
}
}
int main(int argc, char* argv[])
{
FILE *input_file;
struct student input;
input_file = fopen("f1.txt", "r");
if (input_file == NULL)
{
fprintf(stderr, "\nError!\n");
exit(1);
}
list_t* list = (list_t*)calloc(1,sizeof(*list));
char tmp_name[20];
char tmp_id[20];
int tmp_code = 0;
while (fscanf(input_file, "%d %s %s", &tmp_code, tmp_name, tmp_id) != EOF)
{
list_push_back(list, tmp_code, tmp_name, tmp_id);
}
fclose(input_file);
list_print(list);
return 0;
}
To read a single record into the structure input:
fscanf( input_file, "%d %s %s", &input.student_code, input.name, input.ID )
to read a integer and two strings into the relevant members.
fscanf() returns the number of formatted fields successfully assigned, so to display all records in the file in the manner your code attempts:
while( fscanf( input_file, "%d %s %s", &input.student_code,
input.name,
input.ID ) == 3 )
{
printf( "student code = %d, name = %s, ID = %s\n", input.student_code,
input.name,
input.ID ) ;
}
Okay so basically the title says it all. I am working on a project where I get a segmentation fault right after I enter the name of the file I want to open. I created a smaller program that did just that, but when I implement it in my project it does not seem to work. I might be overlooking something. Would be awesome if someone could point it out.
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
//function prototypes
void printmenu();
void getcipher(char **arr, int *count, FILE **infile);
int main()
{
int flag = 1; //exit flag for menu loop
int choices; //user input for menu
int count = 0;
char arr[7000][25]; //store words in this array
FILE *infile = NULL; //input cipher file
while(flag)
{
printmenu();
scanf("%d", &choices);
getchar();
while(choices < 1 || choices > 4)
{
printf("\nInvalid input. Try again...");
scanf("%d", &choices);
getchar();
}//end while
switch(choices)
{
case 1:
getcipher((char **)arr, &count, &infile);
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
flag = 0;
break;
}//end switch
}//end while
return 0;
}
void printmenu()
{
printf("\n%s", "Menu Choices");
printf("\n%-40s%-20s", "Use Cipher text file as cipher key", "Enter 1");
printf("\n%-40s%-20s", "Create cipher using a text file","Enter 2");
printf("\n%-40s%-20s", "Decode existing cipher", "Enter 3");
printf("\n%-40s%-20s\n\n", "Exit Program","Enter 4");
}
void getcipher(char **arr, int *count, FILE **infile)
{
int flag; //flag for getting cipher text file
char buffer[1000]; //buffer for reading in lines
char *token;
int letters = 0; //index for letters
int low; //index for converting to lowercase
//Gets cipher text file
printf("\nEnter the name of the cipher text file: ");
scanf("%s", buffer);
printf("\n%s\n", buffer);
*infile = fopen(buffer, "r");
if(!(*infile))
{
printf("Unable to open file. Exiting...");
exit(1);
}//end while
//inputs words from cipher text file to array
while(fgets(buffer, 1000, *infile))
{
token = strtok(buffer, " ");
strcat(arr[*count], token);
count++;
while((token = strtok(NULL, " ")) != NULL)
{
strcat(arr[*count], token);
count++;
}//end while
}//end while
printf("\n%d" , *count);
int i = 0;
//print array
while(i < *count)
{
printf("\n%s ", arr[i]);
i++;
}//end while
}
This is my second smaller program that opened a file within a function. I basically copied this into my project.
#include<stdio.h>
#include<string.h>
void openfile(FILE **file);
int main()
{
FILE *file = NULL;
openfile(&file);
return 0;
}
void openfile(FILE **file)
{
char buffer[100];
printf("Enter the name of file: ");
scanf("%s", buffer);
*file = fopen(buffer, "r");
if(*file)
printf("\nSuccess!!");
}
The problem is that you're casting arr, which is char [7000][25], to char ** when passing it to getcipher. These two declarations are incompatible. The first is a flat 2-dimensional array, while the second is an array of pointers, each of which points to its own secondary array. In general, if you are casting one pointer type to another like this, you are probably introducing a bug.
To fix it, you can change your char **arr declaration in getcipher to char arr[7000][25], or char arr[][25], or char (*arr)[25]. If you don't want to hard-wire the size, you can pass it as a parameter as long as it precedes the array parameter.
Second problem: You have argument int *count in getcipher. In this case it is a pointer to a single int. But you increment it with count++ in a couple places. This will increment the pointer, not the integer it points to. Change it to (*count)++;
The problem I am having with my program is that I create a linked list, but when I go to print out my linked list it just prints out the last person in the list. It is supposed to print out everyone in the list. This is the only problem that I have in my program and if someone could point me in the right direction it would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define MAX_PLAYERS 9
#define MAX_STR_LEN 25
typedef struct Player_ {
char name[MAX_STR_LEN];
int number_of_hits;
int number_of_strikes;
struct Player_ *next;
} Player;
int pitch_result(void);
Player *add_player(Player *first_player, const char *name);
void destroy_team(Player *first_player);
void display_line_up(Player* first);
void readFile(Player **lineup, const char* file);
int main(int argc, char *argv[]) {
if(argc < 2){
exit(1);
}
srand(time(NULL));
int strikes = 0;
int hits = 0;
Player *lineup = NULL;
readFile(&lineup, argv[1]);
printf("\nLine up for this team is: ");
display_line_up(lineup);
printf("\n\n%s is batting \n", lineup->name);
for ( ; strikes < 3; ) {
int result = pitch_result();
if (result) {
++hits;
}
else
++strikes;
}
printf("\nScore of game was: %d\n", hits/4);
return 0;
}
void readFile(Player **lineup, const char* file){
FILE *input;
input = fopen(file, "r");
if(input == NULL){
printf("Failed to open");
}
char player[MAX_STR_LEN];
while(fscanf(input, "%s", &player) != EOF){
// printf("\n%s", player);
*lineup = add_player(*lineup, player);
}
}
int pitch_result(void) {
int result;
result = rand() % 2;
return result;
}
void destroy_team(Player *first_player){
Player *temp = first_player->next;
Player *free_player;
while (temp) {
free_player = temp;
temp = temp->next;
free(free_player->name);
free(free_player);
}
}
Player *add_player(Player *first_player, const char *name) {
Player *new_player = (Player*)malloc(sizeof(Player));
int nameLength;
nameLength = strlen(name);
// new_player->name = malloc(nameLength * sizeof(char));
new_player->next = NULL;
strncpy(new_player->name, name, nameLength);
new_player->number_of_hits = 0;
new_player->number_of_strikes = 0;
return new_player;
}
void display_line_up(Player *first){
if(first == NULL)
printf("\nThe list is empty");
else {
while(first != NULL){
printf("\n%s", first->name);
first = first->next;
}
}
}
Here is the file that I read into the program when I run it (stats.txt)
Yadier_Molina
Allen_Craig
Daniel_Descalso
Rafael_Furcal
David_Freese
Matt_Holiday
Jon_Jay
Carlos_Beltran
Matt_Adams
This is the sample output that I was given for my program
Line up for this team is:
Yadier_Molina
Allen_Craig
Daniel_Descalso
Rafael_Furcal
David_Freese
Matt_Holliday
Jon_Jay
Carlos_Beltran
Matt_Adams
Yadier_Molina is batting
Strike!
hit!
Strike!
Strike!
Score of game was: 0
Your add_player function returns a pointer to a node that contains the new player-- and has no connection to the preexisting list (the variable first_player is never even used).
Your readFile function uses this, discarding the old list each time it reads the name of a new player:
*lineup = add_player(*lineup, player);
so the resultant list contains only the last player.
As Beta said, you are not concatenating the players to the list. You can keep a pointer to the last element, which you modify from readFile:
void readFile(Player **lineup, const char* file){
Player* last = NULL;
FILE *input;
input = fopen(file, "r");
if(input == NULL){
printf("Failed to open");
}
char player[MAX_STR_LEN];
while(fscanf(input, "%s", &player) != EOF){
// printf("\n%s", player);
Player* p = add_player(player);
if (!last)
*lineup = p;
else
last->next = p;
last = p;
}
}
And the function add_player just creates a new player so, I would rename it to: create_player(const char* name)
Anyone know how to read a text file into a struct array? I've been trying to figure out how to do so to no avail.
Here's the function header
int getRawData(FILE* fp, struct nameRecord records[], int currSize)
where the first parameter is passed a file already open for reading, the second an array of nameRecord structs, and the third the number of records currently in that array. The function is supposed to read the data from the file into the array placing it at the end of the array. It then returns the total number of records in the array after reading the file.
I'm also at a loss at initializing the number of elements for the nameRecord struct array. We've never been taught memory allocation and the problem doesn't make any mention of how many records are within the files, making initialization an excercise in frustration. So far, I'm taking advice from someone at another forum and using malloc, but I don't even really know what it does.
Some info on the program itself to provide context:
program will ask the user to enter a name (you may assume that the
name will be no more than 30 characters long). It will then find the
popularity of the name between 1921 and 2010 and print out a chart and
graph. The program will then ask the user if they wish to do another
analysis and repeat the process.
The program will pull information from the following data sources in
determining the popularity of a name.
ontario female baby names ontario male baby names
Note that some names are considered both male and female so your
program will needs the data from both files regardless of the name
entered.
My attempt at the function:
//function that reads and places the read files into the struct arrays
int getRawData(FILE* fp, struct nameRecord records[], int currSize) {
int i;
for(i = 0; i < currSize; i++) {
fscanf(fp, "%[^,],%d,%d", records[i].name, &records[i].year, &records[i].frequency);
}
And here's the entire program:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
struct nameRecord {
char name[31];
int year;
int frequency;
};
void allCaps(char[]);
int getRawData(FILE*, struct nameRecord[], int);
void setYearTotals(struct nameRecord, int, int);
void setNameYearTotals(char, struct nameRecord, int, int);
void getPerHundredThousand(int, int, double);
void printData(double);
void graphPerHundredThousand(double);
int main(void)
{
int currSizem = 0;
int currSizef = 0;
struct nameRecord *records;
FILE* fp = NULL;
FILE* fp2 = NULL;
char name[31];
printf("Please enter your name: ");
scanf("%30[^\n]", name);
printf("your name is %s\n", name);
//opening both male and female name files and reading them in order to get the total number of records in the array
fp = fopen("malebabynames.csv", "r");
if (fp != NULL) {
printf("file opened\n");
while(3 == fscanf(fp, "%[^,],%d,%d", records[currSizem].name, &records[currSizem].year, &records[currSizem].frequency)) {
currSizem++;
}
} else {
printf("file failed to open\n");
}
if(currSizem > 0) {
records = malloc(currSizem * sizeof(struct nameRecord));
}
fp2 = fopen("femalebabynames.csv", "r");
if (fp != NULL) {
printf("file opened\n");
while(3 == fscanf(fp2, "%[^,],%d,%d", records[currSizef].name, &records[currSizef].year, &records[currSizef].frequency)) {
currSizef++;
}
} else {
printf("file failed to open\n");
}
if(currSizef > 0) {
records = malloc(currSizef * sizeof(struct nameRecord));
}
return 0;
}
//function that automatically capitalizes the users inputted name
void allCaps(char s[]) {
while(*s != '\0') {
*s = toupper((unsigned char) *s);
s++;
}
}
//function that reads and places the read files into the struct arrays
int getRawData(FILE* fp, struct nameRecord records[], int currSize) {
int i;
for(i = 0; i < currSize; i++) {
fscanf(fp, "%[^,],%d,%d", records[i].name, &records[i].year, &records[i].frequency);
}
return 0;
}
approximately as follows :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
struct nameRecord {
char name[31];
int year;
int frequency;
};
int getRawData(FILE*, struct nameRecord[], int);
int main(void){
const char *MaleFilePath = "malebabynames.csv";
const char *FemaleFilePath = "femalebabynames.csv";
int currSizem = 0;
int currSizef = 0;
FILE* mfp = NULL;
FILE* ffp = NULL;
struct nameRecord *recordsOfMale, *recordsOfFemale;
//opening both male and female name files and reading them in order to get the total number of records in the array
mfp = fopen(MaleFilePath, "r");
if (mfp != NULL) {
int dummy;
printf("file opened\n");
//line count
while(1 == fscanf(mfp, " %*[^,],%*d,%d", &dummy)){
++currSizem;
}
} else {
printf("file(%s) failed to open\n", MaleFilePath);
exit(EXIT_FAILURE);
}
if(currSizem > 0) {
recordsOfMale = malloc(currSizem * sizeof(struct nameRecord));
if(recordsOfMale == NULL){
perror("malloc for Male records");
exit(EXIT_FAILURE);
}
}
rewind(mfp);
if(currSizem != getRawData(mfp, recordsOfMale, currSizem)){
fprintf(stderr, "I could not read a record for the specified number\n"
"at reading %s\n", MaleFilePath);
exit(EXIT_FAILURE);
}
fclose(mfp);
//Do something
free(recordsOfMale);
return 0;
}
//function that reads and places the read files into the struct arrays
int getRawData(FILE* fp, struct nameRecord records[], int currSize) {
int i;
for(i = 0; i < currSize; i++) {
if(3!=fscanf(fp, " %[^,],%d,%d", records[i].name, &records[i].year, &records[i].frequency))
break;
}
return i;
}