I have two functions that uses up a .dat file.
The first function adds a structure of a question and its answers to the file and the other is to view the questions in the file.
The addQues() function is called main inside a loop that inquires if the user wants to add more questions. The problem is when the addQues() function is called the second time and onward, it successfully writes the question to the file but when the viewQues() function is called, the questions are not shown. The size of the file also increases after each succeeding call of addques()
/* the structure is as follows */
typedef struct {
char question[256];
char choiceA[32];
char choiceB[32];
char choiceC[32];
char choiceD[32];
char ans;
int num;
}question;
/* function to add questions */
void addQues(){
FILE *fileptr;
question catcher, ques;
int x;
fileptr = fopen("Questions.dat", "a+");
if(fileptr != NULL){
catcher.num = 0;
while(fread(&catcher, sizeof(question), 1, fileptr)!= 0){}
printf("There are %d questions. Please type in the Question you would like to add.\n\nQuestion: ", catcher.num);
fflush(stdin);
scanf("%[^\n]%*c", &ques.question);
printf("Add four[4] choices to the question\n");
printf("\nChoice a.: ");
fflush(stdin);
scanf("%[^\n]%*c", &ques.choiceA);
printf("\nChoice b.: ");
fflush(stdin);
scanf("%[^\n]%*c", &ques.choiceB);
printf("\nChoice c.: ");
fflush(stdin);
scanf("%[^\n]%*c", &ques.choiceC);
printf("\nChoice d.: ");
fflush(stdin);
scanf("%[^\n]%*c", &ques.choiceD);
printf("\nType the letter of the correct answer of this question.\nAnswer: ");
fflush(stdin);
scanf("%c", &ques.ans);
ques.num = catcher.num+1;
printf("%s", ques.question); /* made this snippet to make sure that white spaces in my input were recorded */
getch();
if(fwrite(&ques, sizeof(question), 1,fileptr) == 1){
printf("File write was successful\n"); /* made this snippet to make sure if writing is successful. and it is successfull everytime */
}else{
printf("File write was unsuccessfull");
}
getch();
fclose(fileptr);
}else{
printf("File either not found or does not exist.");
}
}
/* code view the Questions in the file */
void viewQues(){
FILE *fp;
question ques;
fp = fopen("Questions.dat", "r");
if(fp != NULL){
while(fread(&ques, sizeof(question), 1, fp) != 0){
printf("[%d] %s\n", ques.num, ques.question);
}
fclose(fp);
}else{
printf("File is either not found or does not exist.");
}
}
I am somehow confused because it somethimes works fluidly, sometimes it doesn't.
This is only my 1st semester of taking up C-programming so I still have alot to learn.
I am also quite new to this website please do forgive me if I may have violated any required format.
EDIT:
The program requires the user to input a question, 4 choices, and it's correct answer.
in the addQues function before the program asks for input, it already notifies the user how many questions there are in the file.
example is
There are 0 question/s (this updates when a question is added). lease type in the Question you would like to add.
Question: //user types What is the capital of Philippines?
Enter Choice A: // user types 'Manila'
Enter Choice B: // user types 'Cebu'
Enter Choice C:// user types 'Davao'
Enter Choice C:// user types 'Palawan'
Enter the letter of the correct answer: // User types in 'a'
Expected output would be
[1] What is the capital of Philippines?
after the second call and onwards the output that it shows is still only
[1] What is the capital of Philippines?
I am sorry I do not know how to make the sample scenario different from the rest of the text.
Related
Basically, I'm working on this text editor program for a school project that uses simple filing and string functions to create, append, delete, display, duplicate, or search from text files. I've managed to put all the functions together, and my question pertains to my Search() function, which I'll attach at the end of this for reference. If the search keyword is found, the function prints which line it was found in, and it prints the line itself. What I'd like to do is, if possible, change the color of the search keyword when the line gets printed so that it stands out and the user can immediately tell where his keyword is located within the line. I'm not asking this without doing ANY research on the matter; I did some digging and it seems I can make use of ANSI escape sequences or the Windows Console Virtual Terminal Sequences to achieve what I'm trying to do, and I did go through the documentation on the Microsoft website, but unfortunately I'm not yet comfortable with calling windows APIs and I could really use some help figuring out exactly how to go about doing this. Also, apologies in advance if the code I'm attaching seems inefficient or unncessary at times, only started learning C a couple months ago. I am using the gcc compiler with DevC++ on Windows 10.
TIA.
void Search(void) {
FILE *fptr;
char name[20], key[30], line[100];
int linenum=1, found=0;
printf("Enter name of text file to search from, or enter 'exit' to cancel and return to menu: ");
gets(name);
if(strcmp(name,"exit") == 0)
return;
strcat(name,".txt");
fptr = fopen(name,"r");
while(!fptr) { // just some input validation
printf("Error. Text file not found. Make sure it exists and is placed in the same folder as the .exe file for this program.");
fclose(fptr);
printf("\n\nEnter name of text file to search from, or enter 'exit' to cancel and return to menu: ");
gets(name);
if(strcmp(name,"exit") == 0)
return;
strcat(name,".txt");
fptr = fopen(name,"r");
}
printf("Enter your search keyword (remember, it is case sensitive): "); //searching staarts here
gets(key);
while(!feof(fptr)) {
fgets(line,100,fptr);
if(strstr(line,key)) {
printf("Keyword found in line %d:\n", linenum);
printf("----------------------------------------------------------------------------------------------\n");
printf("%s",line);
printf("----------------------------------------------------------------------------------------------\n\n");
found=1;
}
linenum++;
}
if(!found)
printf("Keyword not found in file.");
printf("\nPress any key to return to main menu: ");
getch();
}
The reason I used the long ------------ separators is that I want to differentiate the contents of a text file from the contents of what's written in the console window.
Basically, you can rely on string class to complete this task, use string :: find to extract the location of the key, and then use string:: substr to print the value of the key.
Refer to the code below:
void Search(void) {
...
printf("Enter your search keyword (remember, it is case sensitive): "); //searching staarts here
gets_s(key);
while (!feof(fptr)) {
fgets(line, 100, fptr);
if (strstr(line, key)) {
std::string str(line);
printf("Keyword found in line %d:\n", linenum);
printf("----------------------------------------------------------------------------------------------\n");
int pos = str.find(key);
int len = strlen(key);
int len_t = strlen(line);
if (pos != 0)
{
printf("%s", str.substr(0, pos).c_str());
printf("\x1b[31m%s", str.substr(pos, len).c_str());
printf("\x1b[0m%s\r\n", str.substr(len+pos, len_t).c_str());
}
else
{
printf("\x1b[31m%s", str.substr(pos, len).c_str());
printf("\x1b[0m%s\r\n", str.substr(pos+len, len_t).c_str());
}
printf("\x1b[0m----------------------------------------------------------------------------------------------\n\n");
found = 1;
}
linenum++;
}
if (!found)
printf("Keyword not found in file.");
printf("\nPress any key to return to main menu: ");
getch();
}
Debug:
Alternatively you could simply use the Windows API console functions:
#include <stdio.h>
#include <windows.h>
int main()
{
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hstdout, FOREGROUND_RED|FOREGROUND_INTENSITY);
printf("hello ");
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN|FOREGROUND_INTENSITY);
printf("world");
return 0;
}
Essentially, I printed to a binary file using fseek() and fwrite(). However, I want to read the contents from a specific line into a structure. I also used fseek() and fread() to obtain the contents. I prompted the user to enter a code. From what I have learnt, I would use the value obtained from the user to use in the fseek function to get the specific line to start read from. Apparently, the fseek to read the contents does not work, I am getting gibberish essentially when it is displayed on the screen. Assistance is greatly appreciated.
#include <conio.h>
#include <stdio.h>
typedef struct registered
{
int compcode;
char compname[20];
int pinID;
int custID;
char IDtype[15];
int compID;
}REGISTERED;
void AddUpdate(REGISTERED info);
void SellPetrol();
void main(){
REGISTERED info = {0, "Apple", 0, 0, "passport", 0};
REGISTERED list;
AddUpdate(info);
SellPetrol();
}
void AddUpdate(REGISTERED info){
int choice;
FILE *registryfile = NULL;
registryfile = fopen("Sales.dat", "ab");
if (registryfile == NULL){
perror("Error: ");
}
else{
do{
printf("Company Code: ");
scanf("%d", &info.compcode);
printf("Company Name: ");
scanf("%s", &info.compname);
printf("Pin: ");
scanf("%d", &info.pinID);
printf("Customer ID: ");
scanf("%d", &info.custID);
printf("ID type: ");
scanf("%s", &info.IDtype);
printf("Company ID: ");
scanf("%d", &info.compID);
fseek(registryfile, (info.compcode - 1) * sizeof(REGISTERED), SEEK_SET);
fwrite(&info, sizeof(REGISTERED), 1, registryfile);
printf("Enter choice: ");
scanf("%d", &choice);
}while(choice == 1);
}
printf("\tCompany Code: %d\t\n", info.compcode);
printf("\tCustomer ID: %d\t\n", info.custID);
fclose(registryfile);
}
void SellPetrol(){
int code = 0, PIN;
REGISTERED list;
FILE *registryfile = NULL;
registryfile = fopen("Sales.dat", "rb");
if (registryfile == NULL){
perror("Error: ");
}
else{
printf("Please enter the company code: ");
scanf("%d", &code);
// printf("Please enter the PIN: ");
// scanf("%d", &PIN);
rewind(registryfile);
fseek(registryfile, (code - 1) * sizeof(REGISTERED), SEEK_SET);
fread(&list, sizeof(REGISTERED), 1, registryfile); //reads data into list
fflush(stdin);
printf("Company Code: %d\n", list.compcode);
printf("Company Name: %s\n", list.compname);
printf("Pin: %d\n", list.pinID);
printf("Customer ID: %d\n", list.custID);
printf("ID Type: %s\n", list.IDtype);
printf("Company ID: %d\n", list.compID);
}
fclose(registryfile);
}
It seems whichever method you're using to learn C is causing troubles, as the mistakes you seem to be making are common. I suggest reading a book, such as K&R2E... Do the exercises as you stumble across them; don't move on until you've completed them, and ask questions about them if necessary.
Don't fflush(stdin). fflush doesn't do what you think it does.
Check return values for functions such as fopen, scanf, fseek, fread, even fwrite. You'll probably find that your fread or scanf is returning a value indicating failure, hence the gibberish you speak of.
Be aware that C uses pass-by-value semantics ONLY. The source of at least one error in your code is a misunderstanding regarding these semantics. Namely, AddUpdate has no way to modify the variable declared within main, as it recieves a copy of that variable; at this point it seems void AddUpdate(REGISTERED info) should be void AddUpdate(void) and info should be declared within AddUpdate.
scanf("%s", &info.compname); probably doesn't do what you think it does. The %s directive tells scanf to read (metalinguistically speaking) a word (that is, a whitespace-delimitered token), not a line (a newline delimitered token), of user input. You probably want int x = scanf("%19[^\n]", info.compname); or better yet, char *x = fgets(info.compname, sizeof info.compname, stdin);...
void main() is unportable, and so is #include <conio.h>. You probably want int main(void) and ... you don't appear to be using any functions from <conio.h>, so you probably don't want anything in place of that. In C99, a main function that has no return statement will implicitly return 0; without a warning issued.
I've been working on this program for my job that I'm trying to make an inventory of tools. I'm very new to programming if there is an alternative rout to take on this I'm open to looking in to it.
My first case works. All it does is ask the user for a nomenclature, part number(P/N), and serial number (S/N).
The second case I'm trying to make it print the list of data.
My goal for this is to get my problem fixed for my second case
#include<stdio.h>
#include<stdlib.h>
main()
{
FILE * fp;
int qty;
int menu;
char nomen[26];
char pN[26];
char ans;
//Test to see if file exist
fp = fopen("Metro Inventory.txt", "w");
if (fp == NULL)
{
printf("*Error opening file*");
fprintf(fp,"*Error opening file*");
exit(1);
}
//Intro Header
fprintf(fp,"List of Special Tools:");
fprintf(fp,"\t\t\tPart Number:");
fprintf(fp,"\t\t Quantity:\n\n");
printf("Metro Aviation Tools List\n\n");
printf("What would you like to do?\n");
scanf("%d", &menu);
//loop of switch asking for nomenclature
do
{
switch (menu)
{ //Case 1 adds new content
case(1):
{
printf("Enter Nomenclature(no spaces):\n");
scanf("%s", nomen);
fputs(nomen, fp);
fputs("\t\t\t",fp);
//Part Number
printf("What is the part number?\n");
scanf("%s", pN);
fputs(pN, fp);
fputs("\t\t\t", fp);
//Quantity
printf("What is the quantity?\n");
scanf("%d", &qty);
fprintf(fp,"%d",qty);
fputs("\n", fp);
break;
fclose(fp);
}// Case 2 Edits content
case(2):
{
int c;
fp = fopen("Metro Inventory.txt", "r");
if (fp)
{
while ((c = getc(fp)) != EOF)
putchar(c);
fclose(fp);
}
fclose(fp);
break;
}
default : printf("Thank you");
break;
}//end switch
printf("To add tool type Y.\n To exit type N.\n");
getch();
scanf("\n%c", &ans);
//loop
}
while ((ans == 'Y')||(ans == 'y'));
if ((ans == 'N')||(ans=='n'));
{
exit(1);
}
getch();
return 0;
}
I haven't done file I/O for C for quite a long time however, a quick look into your program reveals that the time when you set/modify the value of menu is at line 26/27. Then, your loop starts at line 29. After that, there isn't any instruction to set/modify your menu value.
Later on at line 73 to 75, you are asking for input before the loop scope ends. This input is only used later on in another loop. What I'd suggest to you is to remove the whole switch case structure and allow the program to start away continue to do whatever you want to do. As there isn't any explanation too on why should the user pick 1 for menu or 2.
Edit
It seems that you do not understand my initial comment, so I've taken the liberty to change some parts of your code.
Changes done:
Main() - For C programming, it has to have a type for the program entry point. Either void or int. Should you do int main() make sure to place return 0; before the last braces. Look at the modified code below for clarity.
Position of the code where the input for menu is supposed to happen. I placed it inside the loop so that the user will be prompt every time the loop restarts.
In my initial answer or comment, I've said that in your original code, the point where you modify your variable required for the switch case to work only once and it happens before the loop.
You must think from 1 line to another. What happens at line 1. How does line 1 affect line 2. In this example of yours, at line 26/27, you've set the value of menu to which ever input by the user (input validation is another topic). At that point, it is still linear, nothing loops so it means that your from the point you set the menu (line 26/27) to the point where the program exits (or ends) the value of menu remains static, unchanged.
Removed exit(1); I assumed you wanted the program to end if fp returns null and/or the user has chosen other input for ans. The issue of having an exit point is solved with the next modification I've made (refer to item 4).
Rearranged the code so that if (fp != null) which is the else part in the new code (refer to line 20) the program will allow the file to be written to. And should fp returns null, the whole program will exit with a return 0;.
Modified code
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE * fp;
int qty;
int menu;
char nomen[26];
char pN[26];
char ans;
//Test to see if file exist
fp = fopen("Metro Inventory.txt", "w");
if (fp == NULL)
{
printf("*Error opening file*");
fprintf(fp,"*Error opening file*");
}
else
{
//Intro Header
fprintf(fp,"List of Special Tools:");
fprintf(fp,"\t\t\tPart Number:");
fprintf(fp,"\t\t Quantity:\n\n");
do
{
printf("Metro Aviation Tools List\n\n");
printf("What would you like to do?\n");
scanf("%d", &menu);
//loop of switch asking for nomenclature
switch (menu)
{ //Case 1 adds new content
case(1):
{
printf("Enter Nomenclature(no spaces):\n");
scanf("%s", nomen);
fputs(nomen, fp);
fputs("\t\t\t",fp);
//Part Number
printf("What is the part number?\n");
scanf("%s", pN);
fputs(pN, fp);
fputs("\t\t\t", fp);
//Quantity
printf("What is the quantity?\n");
scanf("%d", &qty);
fprintf(fp,"%d",qty);
fputs("\n", fp);
break;
fclose(fp);
}
// Case 2 Edits content
case(2):
{
int c;
fp = fopen("Metro Inventory.txt", "r");
if (fp)
{
while ((c = getc(fp)) != EOF)
putchar(c);
fclose(fp);
}
fclose(fp);
break;
}
default :
printf("Thank you");
break;
}//end switch
printf("To add tool type Y.\n To exit type N.\n");
getch();
scanf("\n%c", &ans);
//loop
}while ((ans == 'Y')||(ans == 'y'));
}
return 0;
}
I don't know why it is writing only one line in my file
void foo()
{
int ID;
char answer;
FILE *input = fopen("Dane.txt", "w");
do
{
printf("Give ID: ");
scanf("%d",&ID);
fprintf(input, "%d\n", ID);
printf("Exit? y/n ");
scanf("%s", &answer);
fflush(NULL);
}
while (answer != 'n');
fclose(input);
}
Output (in file) is only first ID number which I write on console. But where are others?
EDIT: ok I got it. The error was in char answerand it should be char answer[2] and ending while should be while(answer[0] != ...). Before it the program read only one character - the line end. When i hit e.g. "n ENTER" it take only ENTER. Now it take the first char from tab i.e. "n". Thank everybody for help
You are doing some logical mistake. You are asking whether exit or not. If user does not want to exit, then he would press n. So, to continue the loop, the answer should be equal to n, right?
Modified version of your program:
void foo()
{
int ID;
char answer;
FILE *input = fopen("Dane.txt", "w");
do
{
printf("Give ID: ");
scanf("%d",&ID);
fprintf(input, "%d\n", ID);
printf("Exit? y/n ");
scanf(" %c", &answer);
fflush(NULL);
}
while (answer == 'n');
fclose(input);
}
answer has only one space to read and it isn't capable to store string whose length is 1 character or longer.
This won't affect the result, but using input for output file pointer is confusing.
The conditio in while is unnatural.
Try this:
#include <stdio.h>
void foo();
int main() {foo(); return 0;}
void foo()
{
int ID;
char answer[4];
FILE *output = fopen("Dane.txt", "w");
if (output == NULL) return;
do
{
printf("Give ID: ");
if (scanf("%d",&ID) != 1) break;
fprintf(output, "%d\n", ID);
printf("Exit? y/n ");
if (scanf("%3s", answer) != 1) break;
fflush(NULL);
}
while (answer[0] != 'y');
fclose(output);
}
When I ran your function, I got all three numbers I entered in the file:
$ ./a.out
Give ID: 25
Exit? y/n y
Give ID: 33
Exit? y/n y
Give ID: 10
Exit? y/n n
$ cat Dane.txt
25
33
10
However, your question is backwards. You ask, "Exit? y/n" and then exit if the answer is "n" ("no"). The question should be "Continue? y/n", so that when the user answers in the affirmative, it continues.
Also, naming your output filehandle "input" is backwards, and as others have mentioned, your answer variable should be a character array of at least 2 characters, as char answer[2];.
In my program I am supposed to make a rush hour game in C. I am importing the board shown from a text file.
After than I ask the user for input, which is supposed to be the char on the board he wants to move.
My question is when the user picks the char, how can I check if the char he picked exists in the board.txt file, because if it doesn't, I need to ask the user to pick a new character.
This is how the input section of the code looks so far:
char Direction[1];
char Vehicle[1];
int intInput =0;
// get the char input for the type of vehicle
printf("Please enter which vehicle you would like to move:\n");
scanf("%s", &Vehicle);
//THIS IS WHERE I NEED TO CHECK IF THE CHAR PICKED EXISTS IN board.txt
printf(" This is the input: %s\n", Vehicle);
//get the char input for the direction you want to move
printf("Please choose if you want to move right(R) or left(L):\n");
scanf("%s", &Direction);
if(Direction != "r"||"l"){
printf("Please choose a valid direction(R=Right L=Left):\n");
scanf("%s", &Direction);
}
else{
printf("Your move was %s\n", Direction);
}
//get the int input
printf("Enter how far you would like to move:");
scanf("%d", &intInput);
if(intInput<0){
printf("Please enter a positive integer:");
scanf("%d", &intInput);
}
else{
printf("The inpuy is %d", intInput);
}
how I check if the char he picked exists in the board.txt
The best method is to read the data per line into a buffer to read use fgets
And find char in that buffer. To find use strchr
following code illustrate what i mean
FILE * fp;
fp= fopen("board.txt", "r");
char buffer[256];
if (!fp)
{
printf("error");
return;
}
while (fgets(buffer, 256, fp))
{
char *ptr = strchr(str, Direction);
if(ptr)
printf("found\n");
else
printf("Not found\n");
}
fclose(fp);