saving array to a file won't work, program crashes - c

I posted a few days ago already about a problem with my array-program. Well, it is basically a program which lets the user generate an array, safe a specific number in a specific slot, read the array or read a specific slots value. Now I am figuring out, how to let the user save the current array as a file.
this is what I got
void safeFile(){
FILE *f = fopen("list.txt", "a+");
putc(f , list);
fclose(f);
printf("File saved");
start();
}
where's the problem?
My Program crashes everytime I call the function safeFile() .
I played around, came with fputs instead of putc, program won't crash anymore, the file gets created but it's still blank
void safeFile(){
FILE *f = fopen("list.txt", "r+");
fputs(f , list);
fclose(f);
printf("File saved");
start();
}
here is my current full code
would be grateful for advices, im a newb
#include <stdio.h>
#include <stdlib.h>
int list[30];
int x = 0;
int i = 0; // variable used by for-Loop in setList
int j = 0; // variable used by for-Loop in getList
int input;
int option; //start Value
int gvinput; //getValue input
void start();
void getList();
int main()
{
start();
return 0;
}
void setList(int sizeOfList)
{
for (i = x; i <= sizeOfList; i++)
{
list[i] = i;
}
}
void getList(){
for(j = x; j < i ; j++ )
{
printf("At %d we got the value %d \n",j,list[j]);
}
}
void startList()
{
fflush(stdin);
printf("Please enter number between 0 and 30\n ");
scanf("%d",&input);
if(input > 30 || input == 0)
{
printf("The Number is not between 0 and 30\n");
startList();
}
setList(input);
getList();
fflush(stdin);
start();
}
void setValues(int l[])
{
fflush(stdin);
int v;
int loc;
printf("please enter what value you want to safe\n");
scanf("%d",&v);
fflush(stdin);
printf("Where do you want to save it?\n");
scanf("%d",&loc);
l[loc] = v;
printf("we got at slot %d the value %d\n\n",loc,l[loc]);
start();
}
void getValues(int getArray[]){
fflush(stdin);
printf("which slot do you want to read?\n");
scanf("%d",&gvinput);
fflush(stdin);
printf("The value is: %d \n\n",getArray[gvinput]);
start();
}
void safeFile(){
FILE *f = fopen("list.txt", "r+");
fputs(f , list);
fclose(f);
printf("File saved");
start();
}
void start(){
fflush(stdin);
printf("\n");
printf("[L] = generate Slots\n");
printf("[S] = set a Value at specific slot\n");
printf("[G] = get a Value from a specific slot\n");
printf("[F] = safe File");
printf("[X] = exit\n");
option=getchar();
if(option == 'L' || option == 'l'){
startList();
}
if(option == 'S' ||option == 's'){
setValues(list);
}
if (option =='G' ||option == 'g'){
getValues(list);
}
if (option == 'X' || option == 'x'){
printf("Thank you");
}
if (option == 'f' || option == 'F'){
safeFile();
}

int putc( int ch, std::FILE* stream );
putc writes a single char, and you pass an array of ints to it. The same is true for fputs, which writes a null-terminated string. You'll really have to write some code that serializes your data structure to a sequence of bytes to be written to the file.
In your case, since you want to save a list of ints, you can do this with a loop, for example, that is, loop over your array and write each item to the file. You'll also need a function that writes an int (putc isn't good here, since it writes a char). Have a look at printf, if you'd like to stick with C-style IO, otherwise use streams.

If your using putc(), you should be passing char by char.
for(i=0;i<strlen(list);i++)
{
putc(f,list[i]);
}
The list is an array, if you pass the address it means whole array so putc won't work here.

int fputs(const char *s, FILE *stream);
The second argument to the fputs is the stream. Since u use int [10]. u can use fprintf to print to the file.
Also, fflush(stdin); is undefined behaviour

you need to use the loop, but it is not working because the parameters in the putc function are not in the correct order. Try this:
for(i=0;i<strlen(list);i++)
{
putc(list[i],f); //<---------- NOT putc(f,list[i]);
}
first the char and second the stream.
int putc ( int character, FILE * stream );

Related

how to check variable validity and how to send array of structure to function?

I'm working in library system, I've a lot of things going on:(. In addBook function I'm trying to add book information into Array of structure. First I don't know how to set a statement to check all the validity of title, author, isbn and others. I tried to write a statement but it wont work so I removed it! and didn't call the functions since I don't know how to make them work! secondly I want to send the book information to a file so I can store them inside the file and sort alphabetically. whenever I try to send the array and check the txt file it print the address please help :( I'm trying to keep it simple as possible as I can
#include <stdio.h>
#include <stdlib.h>
#define MAX_ISBN 11
#define MIN_ISBN 9
#define MAX_YEAR 2021
#define MIN_YEAR 1500
#define MAX_DAY 31
#define MIN_DAY 1
#define MAX_MONTH 12
#define MIN_MONTH 1
#define MIN_ISBN 9
#define MAX_Title 80
#define MAX_Author 80
struct Book{
int ISBN[MAX_ISBN], Edition[500], Year[MAX_YEAR],DD[MAX_DAY], MM[MAX_MONTH];
char Title[MAX_Title];
char Author[MAX_Author];
};
/*Check_Title function will check user input if it's a valid title or not! */
int Check_Title(char *Title){
int valid_Title = 1;
int len = 0;
int i= 0;
len = strlen(Title);
for(i =0; i <len ; i++)
{
if( Title[i] == "##$%^&*()}{[ ]")
return 0;;
}
return 1;
}
/*Check_Author function will check user input if it's a valid Author name or not! */
int Check_Author(char *Author){
int valid_Name = 1;
int len = 0;
int i= 0;
len = strlen(Author);
for(i =0; i <len ; i++)
{
if( !(isalpha(Author[i])) && (Author[i] != ' '))
{
valid_Name = 0;
break;
}
}
return valid_Name;
}
int Check_Date(int *DD, int *MM,int *YYYY){
if(DD[MAX_DAY] > MAX_DAY || DD[MIN_DAY]< MIN_DAY)
return 0;
if(MM[MAX_MONTH] >31 || MM[MIN_DAY]<1)
return 0;
if(YYYY[MAX_YEAR]>MAX_YEAR || YYYY[MIN_YEAR]<MIN_YEAR)
return 0;
return 1; //if statement true return 1
}
int Check_ISBN(int *ISBN){
if(ISBN[MAX_ISBN] > MAX_ISBN || ISBN[MIN_ISBN] < MIN_ISBN);
return 0;
return 1; //if ISBN VALID
}
// This function is used to check file existence, every time if it's called
//the following functions is user choice to either add a book, delete, view, and view by year -> Switch cases
void addBook(){
system("cls"); //clearing black screen
int Title_Validity = 0, Name_Validity = 0, ISBN_Validity, Date_Validity = 0,n;
struct Book *insert = NULL;
FILE* ptr = fopen("stored.txt","w");
if (ptr == NULL){
printf("Error opening the file! \n");
exit(1);}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
printf("\n\t\t ========================================================================");
printf("\n\t\t ADD NEW BOOK ");
printf("\n\t\t ========================================================================");
printf("\n\n\t\t\tENTER YOUR DETAILS BELOW:");
printf("\n\t\t\t---------------------------------------------------------------------------\n");
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
printf("\t\tHow many Books would you like to insert? ");
scanf("%d", &n);
for(int i = 0; i<n; i++){
insert = (struct Book*)calloc(n,sizeof(struct Book));
//Inputing Title & Check Title validity
//do{
printf("\n\t\t\tBook Title : ");
fflush(stdin);
fgets(insert[i].Title, MAX_Title, stdin);
/*Title_Validity = Check_Title(&insert[MAX_Title].Title);
if(Title_Validity){
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_");
printf("\t\t\t\t\t\t \t\t Invalid Input ! please try again! \n\t\t\t and make sure to not use any digits or special characters! \n ");
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_*_");
}
}while(Title_Validity);*/
//Inputing Author
printf("\n\t\t\tBook Author : ");
fflush(stdin);
fgets(insert[i].Author, MAX_Author, stdin);
//Inputing ISBN
//do{
printf("\n\t\t\tBook ISBN : ");
scanf("%d", &insert[i].ISBN);
// fflush(stdin);
//fgets(insert[i].ISBN, MAX_ISBN, stdin);
/* ISBN_Validity = Check_ISBN(&insert[MAX_ISBN].ISBN);
if(ISBN_Validity == 0){
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_");
printf("\t\t\t\t\t\t \t\t Invalid Input ! please try again! \n\t\t\t and make sure to not to not accedes the range 9~11! \n ");
printf("\n\t\t *_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*__*_*_*_*_*__*_*_*_*_");
}
}while(ISBN_Validity!=0);*/
//Inputing Edition
printf("\n\t\t\tBook Edition (only digits acceptable) : ");
scanf("%d", &insert[i].Edition);
//Inputing Date
printf("\n\t\t\tBook Date [DD MM YYYY] : ");
scanf("%d%d%d", &insert[i].DD,&insert[i].MM,&insert[i].Year);
printf("\n\t\t ========================================================================");
printf("\n\t\t The book %s has been added to the library.", insert[i].Title );
printf("\n\t\t ========================================================================");
}
//
Sort_Save(n,&insert[x].Title,&insert[x].Author,&insert[x].ISBN,&insert[x].Edition,&insert[x].DD,&insert[x].MM,&insert[x].Year);
return;
}
void Sort_Save(int n,char Title[MAX_Title],char Author[MAX_Author], int ISBN[MAX_ISBN], int Edition[], int day[MAX_DAY], int month[MAX_MONTH], int year[MAX_YEAR]){
int i;
struct Book *st;
FILE* fptr = fopen("sorted.txt", "w");
if(fptr == NULL){
printf("Error opening file! \n");
exit(1);
}
for(i=0; i<n; i++){
fprintf(fptr,"%s %s %d %d %d %d %d",st[i].Title,st[i].Author,st[i],st[i].ISBN,st[i].Edition,st[i].DD,st[i].MM,st[i].Year);
fprintf(fptr,"\n");
}
printf("\n");
fclose(fptr);
}
Since you're asking the users how much books they want to add, you have to allocate the block of memory only once, best right after (before the loop) and certainly not again and again in the loop, where it gets initialized with '0' (zero, that's what calloc does).
And opening a file with the mode "w" truncates that file to zero length, i don't think that this is what you want. And why do you open it, when you do not access it, neither for reading nor for writing?
After scanning, you call the Sort_Save function with a bunch of useless parameters (where does the variable 'x' come from?). You should declare the function like this:
int sortSave(struct Book *books, size_t size)
and pass the allocated block (insert) with the specified size (n).
If you want to sort your library, then you should open the existing database for read first ("r"), then read all the stored values into an array, append the new data to that array, call 'qsort' (see man qsort), specify your compare function (where you specify by which parameter your library should be sorted), close the file, open it again in write mode ("w") and finally write all your (sorted) data into that file.
Do not to forget to flush and close the file, nor to free the allocated blocks of memory.
Edit:
As a hint, seperate code from design. First make sure your code works as expected, then add all the fancy stuff, best as a seperate function.

How to check whether a given integer already exists in a file

How do I write a C program to enter a number from the keyboard and store it in a text file called number.dat. If the number exists in the file, display an error message. Program should allow to input numbers until the user inputs -99.
I tried this question, but I could not find how to check whether the integer already exists in the file.
This is my C code answer:
#include <stdio.h>
int main(void) {
int num;
FILE *xPtr;
xPtr = fopen("number.dat", "a");
while (num = -99) {
printf("Enter a number : ");
scanf("%d", &num);
if (num == -99)
break;
fprintf(xPtr, "%d\n", num);
}
return 0;
}
I could not find how to check whether an integer already exists in the file.
Can you please give me a solution for this matter?
There are a few things that could be improved. First of all, your while loop is using an assignment operator for the conditional expression:
while(num = -99)
Instead of assigning it to 99 at the beginning of the loop each time, you could do this:
while(num != -99)
Since you want the block inside of the loop to execute when num is not equal to -99. I would also convert it to a do-while loop, since you are not assigning num before you enter the loop the first time. When you are in the loop, you should be opening an closing the file so it can keep track of any numbers you add. In order to check your file you will need to read AND append, it is now currently set to only append. To read and append you will do the following:
xPtr = fopen("number.dat", "a+");
It might be helpful to add a function called has_num or whatever you choose, which takes the FILE* and checks for an int returning 1 if found and 0 if not. So you will modify your if statement to be
if (num != -99 && !has_num(xPtr,num))
{
fprintf(xPtr, "%d\n", num);
}
So with all of those changes, your code will become
#include <stdio.h>
int has_num(FILE* file, int num)
{
int curr;
int fnd = 0;
while (!fnd && (fscanf(file, "%d\n", &curr) != EOF))
{
fnd = (curr == num);
}
return fnd;
}
int main(void)
{
int num;
FILE *xPtr ;
do
{
xPtr = fopen("number.dat", "a+");
printf("Enter a number : ");
scanf("%d", &num);
if (num != -99 && !has_num(xPtr,num))
{
fprintf(xPtr, "%d\n", num);
}
fclose(xPtr);
} while (num != -99);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *fp; //create a pointer to FILE
char c,n,num;
printf("Enter a Number : ");
scanf("%c",&n);
if(n== -99){
// printf("Enter number greater than -99");
exit(0);
}
else{
fp = fopen("numbers.dat", "r+"); //read file
while ((c = getc(fp)) != EOF) {
num = c;
if(num==n){
printf("Included Number");
exit(0);
}
}
fp = fopen("numbers.dat","w+"); //write new number to file
putc(n, fp);
}
}
You program should successfully append numbers typed by the user to the file, but it has a few problems:
you do not check if fopen() successfully opened the file, you have undefined behavior if fopen() returns NULL.
you do not check if scanf() encountered an input failure. Entering a character that os not a number will cause undefined behavior, most likely an infinite loop appending the previously entered number if any.
you do not close the file. This will not have any adverse effect because all files are automatically closed upon program exit, but it is good style to close them explicitly.
of course you do not check if the number already exists in the file.
For the last problem, you should fopen() the file for both read and write, rewind the file and read all lines, checking if the number is present.
Here is a modified version:
#include <stdio.h>
int main(void) {
int c, num, num1, found;
FILE *xPtr = fopen("number.dat", "w+");
if (xPtr == NULL) {
printf("cannot open file number.dat\n");
return 1;
}
for (;;) {
printf("Enter a number: ");
if (scanf("%d", &num) != 1) {
if (feof(stdin))
break;
printf("invalid input\n");
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF)
break;
} else {
if (num == -99)
break;
rewind(xPtr);
found = 0;
for (;;) {
/* skip all characters that cannot start a number */
if (fscanf(xPtr, "%*[^-+0-9]") == EOF)
break;
if (fscanf(xPtr, "%d", &num2) == 1) {
if (num == num2) {
found = 1;
break;
}
} else {
getc(xPtr); // consume a byte
}
}
if (found) {
printf("number is already in the file\n");
} else {
/* append the number */
fseek(xPtr, 0L, SEEK_END);
fprintf(xPtr, "%d\n", num);
}
}
}
fclose(xPtr);
return 0;
}

String array comparing with user string gives access error

I am trying to build a program which will take in a list of login details (usernames and passwords) from a file and allow you the option to enter a username and password which are compared with the approved logins and a result is given. In my strcmp I am receiving access violation error 0xC0000005.
#include <stdio.h>
#include <conio.h>
#include<stdlib.h>
FILE *fptr;
void main();
void openFile();
void closeFile();
char approvedUsrnames[3][6];
char approvedPassword[3][6];
void main()
{
char userPassword[6], usrname[6], inputChar, fileString[6];
int i;
openFile();
int numofLogins= 3;
if (fptr != NULL)
{
printf("\nReading file with scanf\n");
while (!feof(fptr))
{
for (i = 0; i < 3; i++) {
fgets(approvedUsrnames[i], 6, fptr);
fgets(approvedPassword[i], 6, fptr);
}
}
closeFile();
}
printf("Enter User name: ");
scanf("%s",usrname);
printf("Enter the password <any 6 characters>: ");
for (i = 0; i<6; i++)
{
inputChar = _getch();
userPassword[i] = inputChar;
inputChar = '*';
printf("%c", inputChar);
}//obfuscate the input to the user
/*If you want to know what you have entered as password, to be removed*/
printf("\nYour password is %s:", userPassword);
for (i = 1; i < 3; i++) {
printf("\Username is good %s\n", approvedUsrnames[i]);
if (strcmp(approvedUsrnames[i], usrname == 0)){
printf("\Username is good\n");
if (strcmp(userPassword, approvedPassword[i]) == 0) {
printf("\nPassword is good\n");
}//end nested if
else {
printf("\nPassword is not match\n");
}
}//end if
}//end for
_getch();
}
void openFile()
{
fptr = fopen("approvedLogins.dat", "r");
if (fptr == NULL)
{
printf("Error opening file ! \n");
}
else {
printf("Login file read successfully ! \n");
}
}
void closeFile()
{
fclose(fptr);
}
#anthonygordon
It is very likely that the strings usrname and userPassword aren't being terminated with '\0' (null terminator) a) as the scanf() may attempt to fill in more chars than usrname can capture b) for loop has to iterate only 5 times so that userPassword[5] is to be explicitly set to '\0'. (If the expectation is to use 6 character long username and password, then change the length of array from 6 to 7 and make sure array[6] is filled with '\0') (Remember in 'C' array subscripts goes as 0..(arraysize-1))
Also, once the user name and password matches, break-out from the loop.
You picked specific lengths for your username and password character arrays. This means that you know the amount of characters you want to compare.
In such a case you do not need to add a '/0' to your character array. Simply use the strncmp() function and specify the number of characters to compare in the second parameter.
See: http://www.tutorialspoint.com/c_standard_library/c_function_strncmp.htm
Just a tip:
Test after every bit of code that you add. This way it is easy to know what code caused the problem. Only when you get really experienced (perhaps 4+ years of coding) can you be brave and write more code before testing.

Continue taking input in while loop in c. I've tried fflush

I'm learning data structures in C and I need to take input from the user. I learned from searching other stackoverflow questions that I need to use fflush after I print something.
The issue I'm having is when I type add it doesn't print anything until I break the while loop by entering quit twice. Can someone explain how to fix this and why it happens please?
Here's the code:
#include "stdio.h"
typedef struct S_RacingCar {
char name[8];
int speed;
} RacingCar;
const int MaxCars = 4;
void PrintList() {
printf("List Print...\n");
}
int AddCar(RacingCar *car) {
printf("Enter Name And Speed:\n\n");
char input[16];
fgets( input, 15, stdin);
int ok = 0;
int result = sscanf(input, "%s %d", car->name, car->speed);
if (result == 2) {
ok = 1;
printf("Added:%s Speed:%d\n\n", car->name, car->speed);
fflush(stdout);
} else {
printf("Sorry, error parsing input\n\n");
}
return ok;
}
int main() {
RacingCar allCars[MaxCars];
int numCars = 0;
char command[16];
char input[16];
while( fgets(input, 15, stdin) ){
sscanf(input,"%s",command);
if ( strncmp(command, "quit", 4) == 0){
printf("\n\nBreaking...\n");
break;
} else if ( strncmp(command, "print", 5) == 0){
PrintList();
fflush(stdout);
} else if ( strncmp(command, "add", 3) == 0){
if (numCars < MaxCars) {
numCars += AddCar( &allCars[numCars] );
fflush(stdout);
} else {
printf("Sorry List is Full!!\n\n");
}
}
fflush(stdout);
}
return 0;
}
The output I get after I type print, and then add is:
print
List Print...
add
The cursor is left blinking under add. If I enter quit I get:
print
List Print...
add
quit
Enter Name And Speed:
Sorry, error parsing input
So the program hasn't ended and I'm wondering why. Could someone explain?
To end the program I have to enter quit again:
print
List Print...
add
quit
Enter Name And Speed:
Sorry, error parsing input
quit
Breaking...
<<< Process finished. (Exit code 0)
================ READY ================
The reason that your program behaves weirdly is because it exhibits UB.
Change
int result = sscanf(input, "%s %d", car->name, car->speed);
To
int result = sscanf(input, "%s %d", car->name, &(car->speed));
This is done because sscanf expects an int* but you give it an int.
Also, you can add
setvbuf(stdout, NULL, _IONBF, 0);
at the start of main and remove all the fflush() in your program. The above line flushes the stdout whenever it is written to.
In addition to the other answer, change:
int AddCar(RacingCar *car) {
printf("Enter Name And Speed:\n\n");
to:
int AddCar(RacingCar *car) {
fflush(stdout);
printf("Enter Name And Speed:\n\n");

Reading and Writing to a file in C

I am slowly learning C, but not very well. I have been reading over the countless topics and questions on reading and writing, but I have yet to be able to find anything that makes this all click for me.
I was given the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct YouTubeVideo {
char video_name[1024]; // YouTube video name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct YouTubeVideo Collection[MAX];
int tail = 0;
//-- Forward Declaration --//
void printall();
void insertion();
void branching(char option);
void menu();
int main()
{
char ch;
// TODO: Add code to load save data from file
printf("\n\nWelcome to CSE240: YouTube Classic Hits\n");
do {
menu();
fflush(stdin); // Flush the standard input buffer
ch = tolower(getchar()); // read a char, convert to lower case
branching(ch);
} while (ch != 'q');
return 0;
}
void menu()
{
printf("\nMenu Options\n");
printf("------------------------------------------------------\n");
printf("i: Insert a new favorite\n");
printf("p: Review your list\n");
printf("q: Save and quit\n");
printf("\n\nPlease enter a choice (i, p, or q) ---> ");
}
void branching(char option)
{
switch(option)
{
case 'i':
insertion();
break;
case 'p':
printall();
break;
case 'q':
// TODO: Add code to save data into a file
break;
default:
printf("\nError: Invalid Input. Please try again...");
break;
}
}
void insertion()
{
if(tail < MAX)
{
printf("\nWhat is the name of the video? (No spaces characters allowed)\n");
scanf("%s", Collection[tail].video_name);
printf("\nHow many viewer hits does this video have?\n");
scanf("%d", &Collection[tail].ranking);
printf("\nPlease enter the URL: ");
scanf("%s", &Collection[tail].url);
tail++;
}
else
{
printf("\nERROR: Your collection is full. Cannot add new entries.\n");
}
}
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nVideo Name: %s", Collection[i].video_name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
I am suppose to write the code that will store the collection into a file and the likewise right the code that will load the file and read from it.
Thanks to a fairly helpful TA I was able to formulate the following code for each
void store()
{
FILE * fileName;
fileName = fopen ( "Ranking.dbm" , "wb" );
fwrite ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
fclose (fileName);
}
and
void read()
{
FILE *fileName;
fileName = fopen("ranking.dbm", "rb");
if (fileName != NULL){
fread ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
}
else {
printf("ERROR");
}
}
I believe these each to function but the real problem is I don't think I quite understand how and I believe that since I dont even know how they function, I dont know how to use them in the code.
I added both methods to the given code and came up with this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
struct YouTubeVideo {
char video_name[1024]; // YouTube video name
int ranking; // Number of viewer hits
char url[1024]; // YouTube URL
};
struct YouTubeVideo Collection[MAX];
int tail = 0;
//-- Forward Declaration --//
void printall();
void insertion();
void branching(char option);
void menu();
void store();
void read();
int main()
{
char ch;
read();
printf("\n\nWelcome to CSE240: YouTube Classic Hits\n");
do {
menu();
fpurge(stdin); // Flush the standard input buffer
ch = tolower(getchar()); // read a char, convert to lower case
branching(ch);
} while (ch != 'q');
return 0;
}
void menu()
{
printf("\nMenu Options\n");
printf("------------------------------------------------------\n");
printf("i: Insert a new favorite\n");
printf("p: Review your list\n");
printf("q: Save and quit\n");
printf("\n\nPlease enter a choice (i, p, or q) ---> ");
}
void branching(char option)
{
switch(option)
{
case 'i':
insertion();
break;
case 'p':
printall();
break;
case 'q':
store();
break;
default:
printf("\nError: Invalid Input. Please try again...");
break;
}
}
void insertion()
{
if(tail < MAX)
{
printf("\nWhat is the name of the video? (No spaces characters allowed)\n");
scanf("%s", Collection[tail].video_name);
printf("\nHow many viewer hits does this video have?\n");
scanf("%d", &Collection[tail].ranking);
printf("\nPlease enter the URL: ");
scanf("%s", &Collection[tail].url);
tail++;
}
else
{
printf("\nERROR: Your collection is full. Cannot add new entries.\n");
}
}
void printall()
{
int i;
printf("\nCollections: \n");
for(i = 0; i < tail; i++)
{
printf("\nVideo Name: %s", Collection[i].video_name);
printf("\nRanking (Hits): %d", Collection[i].ranking);
printf("\nURL: %s", Collection[i].url);
printf("\n");
}
}
void store()
{
FILE * fileName;
fileName = fopen ( "Ranking.dbm" , "wb" );
if (fileName != NULL)
{
fwrite ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
fclose (fileName);
}
else {
perror("Following error occurred(): ");
}
}
void read()
{
FILE *fileName;
fileName = fopen("Ranking.dbm", "rb");
if (fileName != NULL)
{
fread ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
fclose(fileName);
}
else {
perror("Following error occurred with fopen(): ");
}
}
Now I am sure anyone who has read this has probably already face palmed themselves cause they see the problem, but I do not. The code does not create the file to write to and likewise it has nothing to read from so I cant even begin to see what is wrong with that.
Now I am not looking for a given answer, but I would really like to know what it is I am doing incorrectly, what concepts I appear to not understand, and how I can go about fixing these. I have done a few hours of research on this already and I realize it is elementary, but I really would like a hand in learning. Its frustrating spending hours on a topic that the professor said should only take a couple of hours to complete at most.
You really should check the return value of fopen() against NULL - if there is a problem opening the file, it will return NULL and set errno. This is probably a permissions mistake, and by checking the return value and printing the error if one is set, you'll get more information on what went wrong.
Minor: Make sure to check the return values for things like fopen, fread, fwrite etc. more often.
Mild: You've got a potential typo in the filename (some operating systems have case-sensitive file names)
Severe: read() doesn't set up a value for tail... :)
I believe you may have a problem with the read function, which does not call fclose on the file handle (by the way, calling it fileName is a little misleading).
Because you leave the file open, it's entirely likely that you won't be able to overwrite it when you eventually call store. You haven't output any error messages if the file cannot be opened in that function, so it's quite easy to slip under the radar... At least until you wonder why your file date doesn't change.
Otherwise the code looks okay. All it does is dump the entire contents of your array out of memory and read it back in again. What you'll probably want to do is also write out the value of tail, since it is keeping track of how many elements you are keeping. So with minimal code changes, do this:
fwrite ( &tail, sizeof(int), 1, fileName);
fwrite ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
And of course the corresponding calls to fread in your read method.
fread ( &tail, sizeof(int), 1, fileName);
fread ( Collection, sizeof(struct YouTubeVideo), MAX, fileName);
To reiterate: don't forget to close your file!!!!
fclose(fileName);

Resources