How to store data from files to an array in C - c

So, basically this code below need the user to login first, then after the user login it will show the user details like the one stored in the user.txt. after that i dunno how to retrieve back the files from the files then return it as an array, so that i can update e.g change the name of the user, or delete the user details by taking the array index
here is my code
#include <stdio.h>
#include <string.h>
typedef struct {
char fullname[30];
char dob [10];
int contactNo;
int postcode;
}userDetails;
int main ()
{
char username [15];
char pwd [20];
char user_pass [30];
char userfile [100];
FILE *user;
FILE *admin;
userDetails myUser;
admin = fopen ("admin.txt","r");
printf("Please enter your Username\n");
scanf("%s",username);
printf("Please enter your Password\n");
scanf("%s",pwd);
user_pass[strlen(username) + strlen(pwd) + 2];
sprintf(user_pass, "%s;%s", username, pwd);
while (fgets(userfile, 100, admin) != NULL) {
if (strcmp(userfile, user_pass) == 0) {
printf("Authentication as %s successful\n", username);
size_t nread; // Printing the user information
user = fopen("user.txt", "r");
printf("\nHere is the registered user:\n");
if (user) {
while ((nread = fread(myUser.fullname, 1, sizeof myUser.fullname, user)) > 0)
fwrite(myUser.fullname, 1, nread, stdout);
if (ferror(user)) {
}
fclose(user);
}
}
else{
printf("Please enter correct username and password\n");
}
}
}
and let say in the user.txt the file is stored in a format like this
john;12/12/1990;+6017012682;57115
paul;12/12/1221;+60190002122;100022
max;12/11/1990;+60198454430;900000
jamie;12/05/2000;+60190001231;18000
Thank you

how do you read a data from a files and store it to an array, then read specific stored data in the array to be edited?
Steps to store data:
1) - Declare the type(s) of storage variables needed to support your concept. Array of struct perhaps.
2) - Open file ( FILE *fp = fopen("file path", "r"); )
3) - Loop on fgets() to read each line (record) of file
4) - Parse lines, perhaps using strtok and place elements of each line into storage variable you created above.
5) - close file ( fclose(fp); )
The get record part can be done by selecting a record, and returning a re-concatenated string composed of each field of the original record. The prototype could look like this:
void GetRecord(RECORD *pRec, int rec, char *recordStr);
Where storage would be created as an array of struct, and the struct would accommodate the 4 fields you cited, eg:
John;12/12/1990;+6017012682;57115 //example record with 4 fields
#define MAX_RECORDS 10 //arbitrary value, change as needed
typdef struct {
char name[260];
char date[11];
char num1;
char num2;
} RECORD;
RECORD record[MAX_RECORDS];//change size to what you need, 10 is arbitrary for illustration
Code Example to read data into records , and retrieve a record, could look like this:
(example only, very little error checking)
void GetRecord(RECORD *pRec, int rec, char *record);
int main(void)
{
FILE *fp = {0};
char recStr[260];
char *buf;
char line[260];
int i;
char strArray[3][7];//simple array, 3 string of 7 char each (enough for NULL terminator)
i = -1;
fp = fopen ("admin.txt", "r");
if(fp)
{
while (fgets (line, 260, fp))//will continue to loop as long as there is a new line
{
i++;
if(i >= MAX_RECORDS) break;//reached maximum records defined, time to leave
buf = strtok(line, ";");
if(buf)
{
strcpy(record[i].name, buf);
buf = strtok(NULL, ";");
if(buf)
{
strcpy(record[i].date, buf);
buf = strtok(NULL, ";");
if(buf)
{
record[i].num1 = atoi(buf);
buf = strtok(NULL, ";");
if(buf)
{
record[i].num2 = atoi(buf);
}
}
}
}
}
}
fclose(fp);
// 2nd argument valid values range from 1 - n (not 0 - n)
GetRecord(record, 3, recStr); //read third record into string "rec"
return 0;
}
void GetRecord(RECORD *pRec, int rec, char *record)
{
int r = rec - 1;//adjust for zero indexed arrays
if((r >= MAX_RECORDS) || (r < 0))
{
strcpy(record, "index error");
return;
}
sprintf(record, "%s;%s;%d;%d", pRec[r].name, pRec[r].date, pRec[r].num1, pRec[r].num2);
}
Note: "coz [you were] rushing and just copy the code, and accidentaly delete the important things",
I have not adhered strictly to your variable names. Adjust what I have done to meet your needs.
Results with your input file look like this:

Related

Storing certain information from a file to a data structure

I am currently learning about to how to data structures in C and I need a little help. I am supposed to take information about classes from a .txt file and store the information in a data structure; but I am having trouble doing so. I am also sure that I am also screwing up a lot of other things in my program, so feel free to bash on my program and tell me what I am doing wrong so I can learn from my mistakes.
Here is one line of information that I am trying to store:
M273 Multivariable Calculus :MWF 0900-0950 2
where the first part is the course number, the second part is the course name, the third part is the days and time the course is available and the last number represents what year you should be in to take the course (2 translates to sophomore).
Below is my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define EMAX 250
typedef struct class{
char *classNumber[EMAX];
char *className[EMAX];
char *classTime[EMAX];
char *classStanding[EMAX];
}class;
void menu(class*info, char buffer[], FILE*file);
void setInformation(class*info, char buffer[], FILE*file);
int main(void)
{
class info[EMAX];
char buffer[EMAX];
File *file;
setInformation(info, buffer, file);
menu(info, buffer, file);
return(0);
}
void menu(class*info, char buffer[], FILE*file)
{
int user_input=0;
do {
printf("\nSelect one of the following options: \n");
printf("1) Print all information about all classes in order of the class number\n");
printf("5) Quit\n");
scanf("%d", &user_input);
if(user_input==1)
{
//getInformation(info, buffer, file);
}
}while(user_input!=5);
}
void setInformation(class*info, char buffer[], FILE*file)
{
size_t count = 0;
char line[50];
char *token;
file = fopen("classes.txt", "r");
while(fgets(line, sizeof(line), file)!=NULL)
{
token=strtok(line, " "); //Only gets the course number
strncpy(info[count].classNumber, token, strlen(token));
count++;
}
fclose(file);
}
As you can tell, I can only extract the course number with this code. I would prefer to store all the data in one while loop and I have tried to extract more information by adding another token to stop as soon as it reaches the ":" before the day and time but I can't figure out how to get it to work. I also get a lot of warnings when I compile this, so I welcome any advice to help my trash code. I appreciate any help
*scanf() is great:
#include <stdlib.h>
#include <stdio.h>
#define EMAX 250
#define STRING(X) #X
#define STRINGIFY(X) STRING(X)
typedef struct class_tag {
char classNumber[EMAX + 1];
char className[EMAX + 1];
char classTime[EMAX + 1];
char classStanding[EMAX + 1];
char foo[EMAX + 1];
} class;
int main(void)
{
char const *input_filename = "test.txt";
FILE *input = fopen(input_filename, "r");
if (!input) {
fprintf(stderr, "Couldn't open \"%s\" for reading :(\n\n", input_filename);
return EXIT_FAILURE;
}
class c;
class *classes = NULL;
size_t classes_size = 0;
while (fscanf(input, "%"STRINGIFY(EMAX)"s %"STRINGIFY(EMAX)"[^:] %"STRINGIFY(EMAX)"s "
"%"STRINGIFY(EMAX)"s %"STRINGIFY(EMAX)"s",
c.classNumber, c.className, c.classTime, c.classStanding, c.foo) == 5)
{
class *tmp = realloc(classes, ++classes_size * sizeof(*classes));
if (!tmp) {
fputs("Not enough memory :(\n\n", stderr);
fclose(input);
free(classes);
return EXIT_FAILURE;
}
classes = tmp;
classes[classes_size - 1] = c;
}
fclose(input);
for (size_t i = 0; i < classes_size; ++i)
printf("%s %s %s %s\n", classes[i].classNumber, classes[i].className, classes[i].classTime, classes[i].classStanding);
free(classes);
}

Matching text from 2 files

I have written a program that is designed to recover linux system passwords by searching for matching hashes which are present in two text files
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXCHAR 1000
//Declaring Functions to match word in file
int matchfile(char *shadowfilename, char*hashtablefilename);
//shadowfilename for shadow.txt hashtablefilename for hash table
void UsageInfo(char *shadowfile, char * hashtablefile );
//Display usage info on arguments for program
void UsageInfo(char *shadowfile, char * hashtablefile) {
printf("Usage: %s %s <shadowfile> <hashtable>\n", shadowfile,hashtablefile);
}
//main function.
int main(int argc, char *argv[]) {
int result, errcode;
//Display format for user to enter arguments and
//End program if user does not enter exactly 3 arguments
if(argc < 3 || argc > 3) {
UsageInfo(argv[1],argv[2]);
exit(1);
}
system("cls");
//Pass command line arguments into searchstringinfile
result = matchfile(argv[1], argv[2]);
//Display error message
if(result == -1) {
perror("Error");
printf("Error number = %d\n", errcode);
exit(1);
}
return(0);
}
//Declaring Functions to match word in file
//int matchfile(char *shadowfilename, char *hashtablefilename);
//shadowfilename for shadow.txt hashtablefilename for hash table
int matchfile(char *shadowfilename, char *hashtablefilename){
FILE *shadowfile;
FILE *hashtable;
char strshadow[MAXCHAR];
char strhash[MAXCHAR];
shadowfile = fopen(shadowfilename, "r");
if (shadowfile == NULL){
printf("Could not open file %s",shadowfilename);
return 1;
}
hashtable = fopen(hashtablefilename, "r");
if (hashtable == NULL){
printf("Could not open file %s",hashtablefilename);
return 1;
}
//Getting text from the 2 files
while (fgets(strshadow, MAXCHAR, shadowfile) != NULL &&fgets(strhash,MAXCHAR,
hashtable) != NULL){
printf("%s", strshadow);
printf("%s", strhash);
int linenumber = 1;
int search_result = 0;
//Matching words line-by-line
if((strstr(strshadow,strhash)) != NULL) {
//Display line in which matched word is found
printf("A match found on line: %d\n", linenumber);
printf("\n%s\n", strhash);
search_result++;
}
linenumber++;
}
fclose(shadowfile);
return 0;
}
However, I am unable to match the two hash values present in the two files due to the characters in front of them.
hashtable.txt.
This file contains the missing password in plain-text and is corresponding hash values.
The format is as follows: (password):(hash)
banana:$1$$Tnq7a6/C1wwyKyt0V/.BP/:17482:0:99999:7:::
shadow.txt. This file contains the account username in plain-text and is corresponding hash values.
The format is as follows: (user):(hash)
pyc1:$1$$Tnq7a6/C1wwyKyt0V/.BP/:17482:0:99999:7:::
As seen above, the words 'banana' and 'pyc1' prevent the program from detecting the two hashes from being detected.
Could someone tell me the changes I need to make to overcome this ?
Thank you.
Edit:Clarified format of shadow.txt and hashtable.txt
The simplest way to skip characters in string until some condition is met is:
char someString[MAXCHAR];
for (char* ptr = someString; *ptr != '\0'; ptr++) {
if (conditionIsMet(ptr)) {
doSomething();
break;
}
}
In your case, conditionIsMet(ptr) should be comparing *ptr to ':' and in that case, the password hash is under (ptr + 1) (string starting from the next character). I think you can write the rest of the code yourself.

Sorting string containing numbers entered from a file in C?

So I'm working on a program that reads lines from a file containing an "item number", "unit price" and "purchase date" for each line / item. I've made it to the point where I can scan the file and organize it in the chart format required, but I can't figure out how to sort the data by "Item number".
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char ch;
fp = fopen("f.txt", "r"); //open the file named f.txt
if (fp == NULL) //In case we can't find the file, notify the user
printf("File not found\n");
printf("Item \t\tUnit Price\tPurchase Date\n"); //set up the header
while ((ch = fgetc(fp)) != EOF) { //set the character equal to the character next in the file using fgetc, and
//if its not equal to the end of file
if (ch == ',') {
printf("\t\t"); //add two tabs every time a ',' is encountered.
}
else {
printf("%c",ch); //just display the output from the file
}
}
fclose(fp); //closes the file
return 0;
}
Sample input
Sample output
See, I need the output to be sorted by Item number (the far left column).
My idea was to add each line to a string array (char array in c), then from there I don't know how to identify the item number, in order to sort it for the output. I'm slightly familiar with fscanf, but do not know how to apply it here.
Any help is greatly appreciated, thank you.
Okay, I believe it would be nice to break this down into some steps.
Define a struct that is specific for your data
Read a file line by line
For each line, use strtok() to split the string
Add these values into your array of struct
Use qsort() to sort your array of struct
I highly recommend you read more about strtok() and qsort() functions if you are not familiar with them.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// STEP 1
typedef struct
{
int item;
float price;
char date[50];
} Data;
int compare (const void * a, const void * b)
{
Data *dataA = (Data *)a;
Data *dataB = (Data *)b;
return ( dataA->item - dataB->item ); // Ascending order
//return ( dataB->item - dataA->item ); // Descending order
}
int main()
{
FILE * fp;
char line[150];
Data data[3];
int i = 0;
fp = fopen("f.txt", "r");
while (1)
{
// STEP 2
if (fgets(line,150, fp) == NULL) break;
// STEP 3-4
char * pch;
pch = strtok (line,",");
data[i].item = atoi(pch); // item part
pch = strtok (NULL, ",");
data[i].price = atof(pch); // unit price part
pch = strtok (NULL, ",");
strcpy(data[i].date, pch); // purchase date part
i++;
}
printf("##### BEFORE #####\n");
printf("Item \t\tUnit Price\tPurchase Date\n"); //set up the header
for (int k = 0; k < 3; k++)
{
printf("%d\t\t%f\t%s", data[k].item, data[k].price, data[k].date);
}
// STEP 5
qsort (data, 3, sizeof(Data), compare);
printf("\n##### AFTER #####\n");
printf("Item \t\tUnit Price\tPurchase Date\n"); //set up the header
for (int k = 0; k < 3; k++)
{
printf("%d\t\t%f\t%s", data[k].item, data[k].price, data[k].date);
}
fclose(fp);
return 0;
}
Please note that this code is written for your test case only. If your data structure is different (if you have more than three columns etc.) you need to modify the code. Also, you are gonna need to do some more error-handling.
Here is the output:
##### BEFORE #####
Item Unit Price Purchase Date
583 13.500000 10/24/2005
3912 599.989990 7/27/2008
12 19.990000 3/16/2001
##### AFTER #####
Item Unit Price Purchase Date
12 19.990000 3/16/2001
583 13.500000 10/24/2005
3912 599.989990 7/27/2008
Hope this helps.
Baris

Reading from a text file that contains a list

The purpose of the program is to read a text file that contains a list of 55 authors and titles of books. The format of the list goes (author name, booktitle). I can use malloc, strlen, strtok, and strcopy. So far I got the program to read out the names of the authors but I am stuck on how to get the program to read the titles of the books.How would I get the program to read the titles of the books from the text file? I know that there are errors in this code so please be kind .
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void loadBookName(char* filename, char* authorName[55], char* bookName[55]);
int main(int argc, char* argv[])
{
//Create two arrays each with length 55
char* authorName[55];
char* bookName[55];
//Ask the user for the name of the file
char fileName[30];
//Insert your code here
printf("Please enter the name of the file\n");
scanf("%s", fileName);
//Call the method loadBookName
loadBookName(fileName, authorName, bookName);
return 0;
//Print the two arrays to test if the two arrays were correctly loaded with the data
int i = 0;
printf("%-30s%-40s\n", "Author", "Book");
for (i = 0; i < 55; i++) {
printf("%-30s%-40s\n", authorName[i], bookName[i]);
}
}
/*
loadBookName method
This method is responsible for:
1. Take a file containing a book name and the author name as input
2. Open the file
3. Read the information in the file and store it in two arrays: authorName, bookName
4. Return the two arrays to the main method.
*/
void loadBookName(char* filename, char* authorName[55], char* bookName[55])
{
int i;
char string_array[80];
const char comma[2] = ",";
//Open the file
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("Failed to open file\n");
exit(1);
}
for (i=0; i<55; i++)
{
fgets(string_array, 80, fp);
authorName[i] = strtok(string_array, comma);
printf("%s\n", *authorName);
}
//Close the file
fclose(fp);
}
when I run the program in terminal it asks me to enter the filename (books.txt). Then when I enter the file name, the program prints a list of 55 authors.
I don't have a compiler in front of me, so excuse the compilation error if it has any. But I think you can try something as below, within your existing code:
UPDATED:
After comments, I've updated one line. This is compiled and working.
Assumptions: User need to take care of error-handling e.g. file not present, file unable to open, buffer overflows etc.
char *token;
for (i=0; i<55; i++)
{
//fgets(string_array, 80, fp);
//This will take care in case if lines are less than 55
if(!fgets(string_array, 80, fp))
break;
//Get the author
token = strtokstring_array, comma);
authorName[i] = token; // or use string copy functions
//Get book name
while( token != NULL )
{
printf( " %s\n", token ); //this shall print author name
token = strtok(NULL, comma);
bookName[i] = token;
printf( " %s\n", token ); //this shall print book name
//EDIT: This is additional line after suggestions
token = strtok(NULL, comma);
}
}
Simple way of separating strings with strlcpy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void )
{
size_t i = 1;
char *authorName, *bookName;
const char *a_line_in_a_file =
"Lewis Carroll,The Hunting of the Snark";
const char *title = a_line_in_a_file;
while ( *title != ','){
title++;
i++;}
authorName = malloc(i);
bookName = malloc(strlen(title));
title++;
#if __BSD_VISIBLE
strlcpy(bookName, title, strlen(title) + 1);
strlcpy(authorName, a_line_in_a_file, i);
#else
snprintf(bookName, strlen(title) + 1, "%s", title);
snprintf(authorName, i, "%s", a_line_in_a_file);
#endif
printf("%-30s%-40s\n", authorName, bookName);
free(authorName);
free(bookName);
return 0;
}

Saving unwanted data to an error file

Hi I currently have a piece of code that grabs names from a file and then saves it to another.
However I would now like to save any invalid information to a fixed error file and was wondering how I'd go about it
My code:
Struct:
struct Person{
char fName[16]; //string to store the persons first name
char lName[21]; //string to store the persons last name
};
Main
int main(){
int recordCount = 0; //used to keep track of the number of records currently in memory
struct Person *records;
records = malloc(sizeof(struct Person));
records = open(&recordCount, records);
records = addRecord(&recordCount, records);
save(recordCount, records);
return 0; //End the program and return 0 to the operating system
}
open(&recordCount, records) function:
struct Person* open(int *rCount, struct Person *records){
FILE *recordFile;
char fileName[30] = {'\0'};
int i = *rCount;
char test;
puts("Enter a filename to open :");
scanf("%s", fileName);
if((recordFile = fopen(fileName,"r"))==NULL){
printf("Couldn't open the file: %s\n",fileName);
exit(1);
}
else{
test = fscanf(recordFile,"%s %s", records[i].fName,records[i].lName);
while(test!= EOF){
i++;
records = realloc(records,(i+1)*sizeof(struct Person));
test = fscanf(recordFile,"%s %s", records[i].fName,records[i].lName);
}
fclose(recordFile); // close the file
}
*rCount = i;
return records; //add i (records read from the file) to rCount (the current record count)
}
addRecord(&recordCount, records) function
struct Person* addRecord(int* rCount, struct Person *records){
int valid = 0; //used to indicated valid input
int length = 0; //used to store the string lengths
int i = 0; //used in the for loops
char fNameTest[16]; //temporary storage of input to be checked before adding to records
char lNameTest[21]; //temporary storage of input to be checked before adding to records
//Checking the length of data input for fName
do{
length = strlen(fNameTest);
if(length < 16){
for(i=0;i<=length;i++)
records[*rCount].fName[i] = fNameTest[i]; //if correct insert the record at the index determined by rCount
valid=1;
}
else{
valid = 0;
}
}while(valid!=1);
//Checking the length of data input for lName
do{
length = strlen(lNameTest);
if(length < 21){
for(i=0;i<=length;i++)
records[*rCount].lName[i] = lNameTest[i]; //if correct insert the record at the index determined by rCount
valid=1;
(*rCount)++; //At this point ID,fName and lName have been stored so increment rCount
}
else{
valid = 0;
}
}while(valid!=1);
records = realloc(records,((*rCount)+1)*sizeof(struct Person));
return records; //return rCount as the new updated recordCount
}
save(recordCount, records) function
void save(int rCount, struct Person *records){
FILE *recordFile; //file handle
char fileName[30] = { '\0'}; //string to store the file name
int i;
puts("Enter a filename to save the records :"); //ask the user for the filename
scanf("%s", fileName); //store the filename: data input should be checked
//here in your program
//try and open the file for writing and react accordingly if there is a problem
if((recordFile = fopen(fileName,"w"))==NULL){
printf("Couldn't open the file: %s\n",fileName);
}
else{ //the file opened so print the records array of Person's to it
for(i=0;i<rCount;i++){
fprintf(recordFile,"%s %s\n",records[i].fName,records[i].lName);
}
fclose(recordFile); //close the file
printf("Records saved to file: %s\n",fileName);
}
}
I was thinking of removing the do-while loops in the addRecords function and replacing them with if statements. And then finally an if statement to check the value of valid. And then if valid=0 point to a function or save the errorfile directly there.
However I am unsure if this is the best way to go (or if my thought process would even work) and wondered if anyone could help.
Edit: Decided to add the type of data I'm dealing with incase anyone wants to create a .txt and run the program
Bob Jones
Franklin Davies
James Donut
EDIT Following the answer below I have updated my code (edited segments below)
EDITED saveFunction
void save(int rCount, struct Person *records){
FILE *recordFile; //file handle
char fileName[30] = { '\0'}; //string to store the file name
int i;
puts("Enter a filename to save the records :"); //ask the user for the filename
scanf("%s", fileName); //store the filename: data input should be checked
//here in your program
//try and open the file for writing and react accordingly if there is a problem
if((recordFile = fopen(fileName,"w"))==NULL){
printf("Couldn't open the file: %s\n",fileName);
}
else{ //the file opened so print the records array of Person's to it
char fileName[sizeof (struct Person) * 2]; // twice needed size
while (fgets(fileName, sizeof fileName, recordFile) != NULL) {
struct Person P;
int n; // Save index where scanning stopped
int cnt = sscanf(fileName,"%15s%21s %n", P.fName, P.lName, &n);
if (cnt != 2 || fileName[n]) {
errorLine(fileName);
// do not increment i;
} else {
// Good to keep
// realloc memory as needed here
records[i] = P;
i++;
}
}
errorLine function:
void errorLine(char *fileName)
{
FILE *errorFile;
//try and open the file for writing and react accordingly if there is a problem
if((errorFile = fopen("error.txt","w"))==NULL){
printf("Couldn't open the file:\n");
}
else{ //the file opened so print the records array of Person's to it
for(i=0;i<rCount;i++){
fprintf(errorFile,"%i %s %s\n",records[i].fName,records[i].lName);
}
fclose(errorFile); //close the file
printf("Records saved to file: %s\n",fileName);
}
}
No doubt I probably implemented the answer incorrectly and now get an error:
error: expected declaration or statement at end of input
Which is found on my last line of the program
Need to limit length of input before attempting to save in structure.
else {
char buffer[sizeof (struct Person) * 2]; // twice needed size
while (fgets(buffer, sizeof buffer, recordFile) != NULL) {
struct Person P;
int n; // Save index where scanning stopped
int cnt = sscanf(buffer,"%15s%21s %n", P.fName, P.lName, &n);
if (cnt != 2 || buffer[n] || MaybeAddtionalTests(&P)) {
SaveBadLine(buffer);
// do not increment i;
} else {
// Good to keep
// realloc memory as needed here
records[i] = P;
i++;
}
}
fclose(recordFile); // close the file

Resources