Problems with running a Program with files - c

I have a school project and that project is making a C programming dictionary which will contain basic C statements and their meanings and uses. These statements and meanings will be inputted by me. Whatever I input will be stored in the file Dictionary.dat.
#include<stdio.h>
#include<conio.h>
#include<string.h>
typedef struct
{
char word[30], meaning[1000];
}lib;
void intro(void);
void updateword(FILE*,lib);
void addword(FILE*,lib);
void showMeaning(FILE*,lib);
void letter(FILE*,lib);
void showAll(FILE*,lib);
int main()
{
char pass[8], choice;
lib a;
FILE *f=fopen("Dictionary.dat","a+b");
printf("Enter Admin code: ");
gets(pass);
if(strcmp(pass,"turla")==0)
{
printf("Welcome to Admin page\n");
printf("What will do?\n(U)-update\t(A)-Add Word\n(S)-Show All\t");
printf("(L)-Show by Letter\n(M)-Show Meaning\n");
while(choice!='E'||choice!='e')
{
scanf("%c",&choice);
if(f!=NULL)
{
switch(choice)
{
case 'U': updateword(f,a);break;
case 'A': addword(f,a);break;
case 'S': showAll(f,a);break;
case 'L': letter(f,a);break;
case 'M': showMeaning(f,a);break;
case 'E': printf("closing");break;
}
}
}}
else
{
printf("W e l c o m e t o C P r o g r a m m i n g D i c t i o n a r y !\n");
printf("\t A Dictionary for C programming terms\n\n");
printf("What would you want to do? do?\n\n (S)-Search terms\t(L)-Search by letter\n(A)-Show All\n");
scanf("%c",&choice);
while(choice!='E'||choice!='e')
{
intro();
switch(choice)
{
case 'A':
case 'a': showAll(f,a); break;
case 'L':
case 'l': letter(f,a); break;
case 'S':
case 's': showMeaning(f,a); break;
case 'E':
case 'e': printf("closing..."); break;
}
}
system("cls");
}
fclose(f);
getch();
return 0;
}
void intro(void)
{
printf("W e l c o m e t o C P r o g r a m m i n g D i c t i o n a r y !\n");
printf("\t A Dictionary for C programming terms\n\n");
printf("What would you want to do? do?\n\n (S)-Search terms\t(L)-Search by letter\n(A)-Show All\n");
}
void updateword(FILE*ptr,lib a)
{
char srchWrd[30],choice,qtn='Y';
printf("Enter Word to update: ");
gets(srchWrd);
while(fread(&a,sizeof(lib),1,ptr))
{
system("cls");
if(strcmp(srchWrd,a.word)==0)
{
printf("What will you change? (W)-Word (M)-Meaning");
scanf("%c",&choice);
while(qtn!='N'||qtn!='n')
{
switch(choice)
{
case 'W':
case 'w': gets(a.word); printf("Do you still want to edit?(Y/N): "); scanf("%c",&qtn); break;
case 'M':
case 'm': gets(a.meaning); printf("Do you still want to edit?(Y/N): "); scanf("%c",&qtn); break;
default: printf("Invalid option. Enter Again");
}
}
fseek(ptr,sizeof(lib)*-1,1);
fwrite(&a,sizeof(lib),1,ptr);
}}
}
void addword(FILE*ptr,lib a)
{
printf("Enter word: ");fflush(stdin);
gets(a.word);
printf("Enter Meaning: ");fflush(stdin);
gets(a.meaning);
fwrite(&a,sizeof(lib),1,ptr);
}
void showMeaning(FILE*ptr,lib a)
{
char wrd[30];
int ctr=0;
printf("Search: ");
gets(wrd);
while(fread(&a,sizeof(lib),1,ptr))
{
if(strcmp(wrd,a.word)==0)
{
printf("\t%s",a.meaning);
ctr ++;
}
}
if(ctr==0)
printf("No word or symbol found in Dictionary");
}
void letter(FILE*ptr,lib a)
{
char ltr;
int ctr;
printf("Enter Letter");
scanf("%c",&ltr);
while(fread(&a,sizeof(lib),1,ptr))
{
if(ltr==a.word[0])
{
printf("%s - %s",a.word,a.meaning);
ctr++;
}
}
if(ctr==0)
printf("No search results");
}
void showAll(FILE*ptr,lib a)
{
while(fread(&a,sizeof(lib),1,ptr))
printf("%s - %s",a.word,a.meaning);
}
I have problems inputting the first word because It will always ask me to enter a word even if the else statement terminates. I am using C language, not C++.

I got your problem. You problem is at this line.
while(choice!='E'||choice!='e')
You're using OR operation instead of AND operation. So, that line should be
while((choice != 'E') && (choise != 'e')).
Why your code failed when entering e or E:
If you entered e then,
while( `e` != `E` || `e` != `e`)
----------
^
returns true. so controller goes to the while loop.
same with E too.
How && works:
If you entered e then,
while( `e` != `E` && `e` != `e`)
----------
^
returns true and checks second condition
while( `e` != `E` || `e` != `e`)
---------- ---------
^ ^
returns true. returns false. Condition failed. Don't enter into while.
Edit: 2nd problem
In else block, in switch-case add this instruction:
scanf("%c",&choice);
ohterwise your loop executes continuously.

There seem to be verious issues with your program. I'll address the mixed scanf and gets input I've hinted at in my comment here.
When you want to add an entry, you type 'A'. Nothing happens. That's because the input is buffered and is not sent to the program until a new-line was received, i.e. until the user presses return. Which the user does, of course, because nothing happend when 'A' was pressed. The 'A' still sits in the buffer, however. Now you ask the user to provide a word, which is read from the bufer with gets, which reads input until the end of a line is found.
But yout input bufer looks like this:
A newline w o r d newline
The 'A' has been consumed by scanf, but the newline hasn't. The next line you read is an empty line.
I suggest that you write a little framework for your most typical cases: Picking an item from a menu by typing a single letter plus newline and readlin a line of input. This still won't be ideal, because the normal input from the terminal doesn't lend itself to fancy menus, but it's a start. You should look into ncurses or possibly the options in <conio.h> if you want to write pretty DOS-style menus.
Anyway, here's a suggestion that should get you an idea:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int read_key()
{
char buf[40];
char key;
if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;
if (sscanf(buf, " %c", &key) == 0) return 0;
return key;
}
int read_line(char *buf, int max)
{
int len;
if (fgets(buf, max, stdin) == NULL) return -1;
len = strlen(buf);
if (len) buf[--len] = '\0';
return len;
}
int main()
{
char buf[40];
int key;
int len;
printf("\nW e l c o m e !\n\n");
for(;;) {
printf(" (L) Look\n");
printf(" (R) Register\n");
printf(" (Q) Quit\n");
printf("\n");
key = read_key();
switch (key) {
case 'l':
case 'L':
printf("You are in the school library in a maze of "
"twisted aisles, all different.");
break;
case 'r':
case 'R':
printf("Enter your name:\n");
len = read_line(buf, sizeof(buf));
if (len < 0) goto quit;
if (len) {
printf("Your name is %d letters (and spaces) long.\n", len);
}
break;
case 'q':
case 'Q':
case -1:
quit:
printf("Goodbye.\n");
exit(0);
break;
default:
printf("Oh, the letter '%c'. That's not on the menu.\n", key);
}
printf("\n");
}
}
I haven't looked too closely at the rest of your code, but it doesn't look too solid to me. For example, the showAll function is horrid with a never-ending while loop and an ad-hoc fread where you should probably be using fgets. It is also customary to keey a dictionary in memory and commit the changes to disk after the program has terminated.

Related

How can I reprogram this in such a way that, that I don't need to use any sort of variable?

This my code:
#include <stdio.h>
#include <conio.h>
int processChoice()
{
int choice = -1; //I need to execute this code without using any variable
printf("\nMake a Choice (1, 2, 3 or 0): ");
scanf("%d",&choice);
printf("%d",choice);
switch(choice)
{
case 0:
printf("\nExiting...\n");
break;
case 1:
printf("\nDrawing rectangle...\n");
break;
case 2:
printf("\nDrawing Right triangle...\n");
break;
case 3:
printf("\nDrawing isosceles triangle...\n");
break;
default:
printf("\n** Invalid Choice! **\n");
choice = -1;
}
return choice;
}
void showMenu()
{
printf("\nMenu:");
printf("\n1. Draw Rectangle");
printf("\n2. Draw Right triangle");
printf("\n3. Draw isosceles triangle");
printf("\n0. Exit program\n");
}
int main()
{
int x = -1;
do
{
showMenu();
}while(processChoice() != 0);
return 0;
}
That's my code here I used a variable "int Choice = -1;" I'm supposed to execute the same code without using any variable as per guidelines of my mentor.
I'm expecting the same code to be executed without using any variable.
Maybe your mentor means that this declaration in main
int x = -1;
is not used and should be removed.
As for the function processChoice then in any case you need to enter a value from the user. I see the only possibility to write the function without using a variable the following way with using function getchar
int processChoice( void )
{
printf("\nMake a Choice (1, 2, 3 or 0): ");
switch( getchar() )
{
case '0':
printf("\nExiting...\n");
while ( getchar() != '\n' );
return 0;
case '1':
printf("\nDrawing rectangle...\n");
while ( getchar() != '\n' );
return 1;
case '2':
printf("\nDrawing Right triangle...\n");
while ( getchar() != '\n' );
return 2;
case '3':
printf("\nDrawing isosceles triangle...\n");
while ( getchar() != '\n' );
return 3;
default:
printf("\n** Invalid Choice! **\n");
while ( getchar() != '\n' );
return -1;
}
}

C code acting weird. Sometimes, it takes input, sometimes it doesn't

I'm making a multi-feature command-line application where users have features like encrypt-decrypt a string, check string palindrome and reverse a string, and I started to write my whole code with the encrypt-decrypt feature, but apparently it is not working as expected, sometimes it encrypts/decrypts the string, the same code when executed again exits itself without taking the string input! I have even inserted the fflush(stdin), but no luck!
#include <stdio.h>
void encryptDecrypt();
// void checkPalindrome();
// void reverseWord();
void main()
{
int choice;
printf("\nWelcome to Jeel's multi-feature C App\n\n");
printf("1. Encrypt-Decrypt a word\t2. Check Palindrome\t3. Reverse a word\n\n");
printf("Enter a feature: ");
scanf("%d", &choice);
switch (choice)
{
case 1:
fflush(stdin);
encryptDecrypt();
break;
case 2:
// checkPalindrome();
break;
case 3:
// reverseWord();
break;
default:
break;
}
}
void encryptDecrypt()
{
fflush(stdin);
char eOrD;
printf("\nWelcome to the World of Encryption & Decryption! We're so glad that you're here!\n\n");
printf("Enter 'e' if you want to encrypt a word or 'd' if you want to decrypt a word (e/d): ");
scanf("%c", &eOrD);
if (eOrD == 'e' || eOrD == 'E')
{
fflush(stdin);
char *word;
printf("\nGreat! Now enter a word to encrypt it: ");
fflush(stdin);
gets(word);
char *ptr = word;
for (int i = 0; i < sizeof(ptr); i++)
{
if (*ptr != '\0')
{
*ptr = *ptr + 7;
ptr++;
}
}
printf("\nEncrypted string is: %s, which is encrypted with the key: %d", word, 7);
}
else if (eOrD == 'd' || eOrD == 'D')
{
fflush(stdin);
char *deWord;
printf("\nGreat! Now enter a word to decrypt it: ");
gets(deWord);
char *dePtr = deWord;
for (int i = 0; i < sizeof(dePtr); i++)
{
if (*dePtr != '\0')
{
*dePtr = *dePtr - 7;
dePtr++;
}
}
printf("\nDecrypted string is: %s, which is decrypted with the key: %d\n", deWord, 7);
}
else
{
printf("Invalid input! Please try again!");
}
}
The best and most portable way to clear the stdin is using this:
void clearStream()
{
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
}
Also the following is incorrect, create an array instead of the pointer:
char *word;
gets(word); //word is a pointer, gets will not create a block of memory for it

How to get functions to run correctly when implemented into a switch case statement

UPDATE: The issue seems to be related to the scanf("%[^\n]s", message); line because when the [^\n] is removed the function works but does not consider whitespace. The function alone works when called in main alone but does not print correctly with the menu.
I have two separate functions which have proven to work correctly when simply called in main, however I need to combine all these functions into one code, and call them via a switch case menu for the user. When I implement this, the individual codes do not work the same as there is a printing error. The code is for rotation ciphers, and one function has been included with the switch case menu for the user. When the encryptRK() function is called alone (i.e. without the switch case menu) it correctly prints the first line and then takes the user input and provides the correct output. When put in this singular code with the user menu in main, it no longer works and prints "Enter a message to encrypt: Enter rotation key:" all on one line and will not accept an input to encrypt, even when \n is entered in the printf statement. Why will this code not work with the menu if it works when called alone?
#include <stdio.h>
char encryptRK(char character, int key);
char decryptRK(char charcter, int key);
int main() {
char character;
int key;
printf("Please select an option: \n");\
printf("a) Encrypt a message using rotation cipher with key given\n");
printf("b) Decrypt a message using rotation cipher with key given\n");
printf("c) Encrypt a message using substitution cipher with key given\n");
printf("d) Decrypt a message using substitution cipher with key given\n");
printf("e) Decrypt a message using rotation cipher given text only\n");
printf("f) Decrypt a message using substitution cipher given text only\n");
char c;
scanf("%c", &c);
while(c > 'a' || c < 'f'){
switch(c){
case 'a': encryptRK(character, key);
break;
case 'b': decryptRK(character, key);
break;
/*case 'c': encryptSK(character, key);
break;
case 'd': decryptSK(character, key);
break;
case 'e': decryptR(character);
break;
case 'f': decryptS(character);
break;*/
default: printf("Unknown option %c\nPlease enter a, b, c, d, e or f\n");
}
}
return 0;
}
// Case 'a': Function for encryptRK()
char encryptRK(char character, int key){
char message[100];
int i;
printf("Enter a message to encrypt: ");
scanf("%[^\n]s", message);
printf("Enter rotation key: ");
scanf("%d", &key);
for(i = 0; message[i] != '\0'; ++i){
character = message[i];
if(character >= 'a' && character <= 'z'){
character = character - 32;
character = character + key;
if(character > 'Z'){
character = character - 26;
}
}
else if(character >= 'A' && character <= 'Z'){
character = (character + key);
if(character > 'Z'){
character = character - 26;
}
}
message[i] = character;
}
printf("Encrypted message: %s", message);
//return message;
}
You have check your character which is grater than a and less then f on while loop. Try to use a>= & <=f
check it out.

unintended loop (C)

I keep getting a duplicate loop when running a Rock Paper Scissors program in C:
#include <stdio.h>
#include <stdlib.h>
int getUserInput(userInput);
int getComputerInput(cpuInput);
int pickWinner(int player, int cpu);
int main()
{
int playerWins = 0;
int compWins = 0;
int ties = 0;
int userInput;
int cpuInput;
int userChoice =1;
int compChoice;
int decision;
while (userChoice != 4)
{
compChoice = getComputerInput();
userChoice = getUserInput(userInput);
printf("computer chose %d\n", compChoice); //for debugging
printf("you chose %d \n", userChoice);//for debugging
decision = pickWinner(userChoice, compChoice);
if (decision == 1)
{
playerWins++;
}
else if (decision == 2)
{
compWins++;
}
else if (decision == 3)
{
ties++;
}
}
printf("Final score is: \nPLAYER: %d \nCOMPUTER: %d \n", playerWins, compWins);
}
//generates a random number for computer, 1=rock 2= paper 3=scissors
int getComputerInput (int cpuInput)
{
srand(time(NULL));
int r = rand() %3 +1;
return r;
}
//prompts user for character input, then converts input into a number to return back to main
int getUserInput(userInput)
{
char playerPick ;
printf("Please choose R, P, or S. (Q for quit)\n");
playerPick = getchar();
switch(playerPick)
{
case 'R' | 'r':
printf("Player chose R. \n");
return 1;
break;
case 'p':
case 'P':
printf("Player chose P. \n");
return 2;
break;
case 's':
case 'S':
printf("Player chose S. \n");
return 3;
break;
case 'q':
case 'Q':
printf("player quit");
return 4;
break;
default:
printf("Invalid choice, choose again \n");
break;
}
}
//method for determining winner
int pickWinner(int player, int cpu)
{
if (player ==1 && cpu ==1)
{
printf("tie\n\n");
return 3;
}
else if (player==1 && cpu ==2)
{
printf("you lose, paper beats rock\n\n");
return 2;
}
else if (player ==1 && cpu ==3)
{
printf("you win, rock beats scissors\n\n");
return 1;
}
else if (player ==2 && cpu ==1)
{
printf("you win, paper beats rock\n\n");
return 1;
}
else if (player ==2 && cpu ==2)
{
printf("tie\n\n");
return 3;
}
else if (player ==2 && cpu ==3)
{
printf("you lose, scissors beats paper\n\n");
return 2;
}
else if (player ==3 && cpu ==1)
{
printf("you lose, rock beats scissors\n\n");
return 2;
}
else if (player ==3 && cpu ==2)
{
printf("you win, scissors beat paper\n\n");
return 1;
}
else if (player ==3 && cpu ==3)
{
printf("tie\n\n");
return 3;
}
}
Output:
it seems to be passing a zero back to the getUserInput method and I cant figure out why.
any hints in the right direction would be VASTLY appreciated.
apologies if this post is not formatted correctly.
thanks in advance
When you enter input, you end the input by pressing the Enter key. That key is actually placed into the input queue as a newline.
So when you read the first character, you will get the character entered (for example 'r'). However, the next character in the input queue is the newline, and that will be what the second call to getchar will give you.
There are ways to skip that. The simplest is simply doing an extra getchar call to discard the next character. However, if that's not the newline (for example if the user entered more than one letter as input) then that will not work.
Another possible solution is to use fgets to read a whole line, and the just get the first character from that line. The problem is if you don't provide a big enough buffer to store the line, you will have the same problem as before.
The only safe solution is to read the input from the user as a character. Then in a loop read until you get the newline character. The characters you read in the loop is simply discarded.
Perhaps something like this function:
void skip_past_newline(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
{
// Do nothing
}
}
Then just call it after you read the user input:
playerPick = getchar();
skip_past_newline();
Please do note a couple of things with the skip_past_newline function as presented above:
The variable that receives the result of getchar is an int variable. This is actually important.
I not only check for the newline in the loop, I also check for EOF. This indicates the used pressed the end-of-file key-combination (Ctrl-Z in the Windows console window) and that you should exit your program. This check is why you need to make the variable an int.
AFAICS, there are at least two problems with getUserInput()
When the user inputs an invalid choice, getUserInput returns without a value, because there is no loop around the code to ask again. I am pretty sure, the compiler warns about this.
To input a value, the user must enter a character and a newline. This is the character read the second time, which produces the output "invalid choice". To prevent this, you must skip the whitespace before reading the next input char.

C program to read the contents of the file and pass it to an array

I want to read the contents of a text file and copy it to 3 arrays. The first 14 lines to 'a' array, next 14 to 'b' array and remaining to c. When I press one to enter the choice, it must display the first 14 lines of the .txt file. When I compile this code which I have given, it gives only the first character to the whole array. Please help and thanks in advance.
My code:
#include<stdio.h>
#include<string.h>
void main()
{
int x,i;
char *a[100],*b[100],*c[100];
FILE *stream,*out;
char ch;
clrscr();
stream=fopen("test.txt","r");
while((ch=fgetc(stream))!=EOF)
{
for(i=0;i<14;i++)
a[i]==ch;
//ch=fgetc(stream);
//printf("%c",ch);
}
fclose(stream);
printf("Enter your choice");
scanf("%d",&x);
switch(x)
{
case 1:
for(i=0;i<14;i++)
printf("%s\n",a[i]);
break;
case 2:
for(i=0;i<14;i++)
printf("%s\n",b[i]);
break;
case 3:
for(i=0;i<14;i++)
printf("%s\n",c[i]);
break;
case 4:
exit(0);
default:
printf("Invalid choice");
break;
}
getch();
}
Current Output:
Enter your choice1
n
n
n
n
n
n
n
n
n
n
n
n
typedef char *CP14[14];
int main(){
int x,i;
char *a[14], *b[14], *c[14];
CP14 *abcp, *p[] = {&a, &b, &c, NULL};
char buffer[14*3*128]={0};//128 : max of one line
FILE *stream;
int ch, nlcount=0;//ch is int for fgetc
int gp = 0;
stream=fopen("test.txt","r");
abcp = p[gp];
(*abcp)[0]=&buffer[0];
for(i=0;i<sizeof(buffer)-1 && (ch=fgetc(stream))!=EOF;++i){
if('\n'== (buffer[i] = ch)){
buffer[i]= '\0';
if(++nlcount == 14){
nlcount = 0;
if(NULL == (abcp = p[++gp]))
break;
}
(*abcp)[nlcount]=&buffer[i+1];
}
}
fclose(stream);
...
You do not need the while loop if you know that the file is going to have 14*3 characters.
Simply read them in three consecutive for loops. Something like:
for(i=0;i<14;++i)
a[i]=fgetc(stream));
for(i=0;i<14;++i)
b[i]=fgetc(stream));
for(i=0;i<14;++i)
c[i]=fgetc(stream));
Also, == is a comparison and not assignment operator.

Resources