this is a program that is giving me many headaches, but I am tackling it!
I want to create a program that basically reads a file called message.txt which would have some texts with a message, let's say: ''Hello I am a program'' and then encrypts that message and puts it in a file called encryptMessage.txt, additionally it will save the key used for the user in the file key.txt. Now this is what I have done so far.
That part is already finished. There's only one last thing that I need to do.
The file message.txt has more than one line. For example:
hello I like programming
this is a test
to see if this program
can read and encrypt many lines
I want the program to read all those lines and then encrypt them and save them in encryptMessage.txt, such as this (let's suppose the key is 3):
khoor L olnh surjudpplqj
wklv lv d whvw
wr vhh wklv surjudp
fdq uhdg dqg hgfu|sw pdq| olqhv
However, I do not know how to make it work. I know I need to use a loop and !feof function or something like that. But I sincerely do not know how to implement, do you have any idea? Thank you very much!
#include <stdio.h>
#include <ctype.h>
#define MAXSIZE 100
int main(void)
{
FILE *message;
FILE *encryptMessage;
FILE *key;
message = fopen("message.txt", "r");
encryptMessage = fopen("encryptMessage.txt", "w");
key = fopen("key.txt", "w");
if ((message == NULL) || (encryptMessage == NULL) || (key == NULL))
{
printf("Error reading file!!!\n");
return 1;
}
int userKey;
char sentence[MAXSIZE];
char q[MAXSIZE];
int i = 0;
printf("Input the text that you want to encrypt:\n> ");
fgets(sentence, 99, message);
// printf("\nThe string that you wrote is:\n%s\n\n", sentence);
printf("Input the key:\n");
scanf("%d", &userKey);
fprintf(key, "%d", userKey);
//printf("\nThe key that you selected is: %d\n\n", userKey);
for(i = 0; sentence[i] != '\0'; ++i)
{
if( ( isupper(sentence[i]) ) || ( islower(sentence[i]) ) )
{
q[i] = sentence[i] + (char)userKey;
}
else
{
q[i] = (sentence[i]);
}
}
q[i] = '\0';
printf("%s", q);
fprintf(encryptMessage, "%s", q);
fclose(encryptMessage);
fclose(key);
fclose(message);
return 0;
}
Here's how you can read entire file:
while(fgets(sentence, MAXSIZE - 1, message)) {
// do something with sentence
}
Here is modified source code: http://pastebin.com/KxAe9KcS
Related
im trying to implement the number guessing game. The game itself works fine. But now I want to add a function which safes the score of the last game (Number of trys and guessed number) in the leaderboard.txt file.
I haven't finished the saveScore method yet, I don't need help with implementing the rest. I wan't to read the data from the file, add the new line and sort it from least to most trys. But I only wan't to save the top 10 of all time.
I need some help to get the following code running. One problem is the code doesn´t even terminate.
I think all the problems are within the saveScore method. (line 18 -25)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define max_length 300
void saveScore(int guess, int randNumber) {
FILE *datei;
datei = fopen("leaderboard.txt", "wb");
char lines[max_length];
char leaderboard[10][max_length];
int line = 0;
while (fgets(leaderboard[line], sizeof(lines), datei) != NULL){
line++;
}
leaderboard[line][max_length] = ("%d, %d", guess, randNumber);
fwrite(leaderboard, sizeof(char), sizeof(leaderboard), datei);
fclose(datei);
}
void startGame(){
int guess = 1;
int randNumber;
int uInput;
randNumber = (rand()%100)+1;
printf("%d", randNumber);
do {
printf("Guess the number between 1-100: \n");
scanf("%d", &uInput);
if (uInput < randNumber){
printf("the number you are looking for is higher.\n");
}
else if (uInput > randNumber){
printf("the number you are looking for is lower.\n");
}
else {
printf("Jackpot it was your %d. try.", guess);
}
guess++;
} while (randNumber != uInput);
saveScore(guess, randNumber);
char playAgain = 'j';
printf("Try Again (j/n): \n");
scanf(" %c", &playAgain);
if (playAgain == 'j') {
startGame();
}
printf("Thank you for playing.");
}
int main() {
srand(time(NULL));
startGame();
return 0;
}
I appreciate any help.
Best Enno
This loop has the problem of being able to overflow leaderboard if line ever reaches 10.
while (fgets(leaderboard[line], sizeof(lines), datei) != NULL){
line++;
}
This line
leaderboard[line][max_length] = ("%d, %d", guess, randNumber);
has a few problems. [max_length] would be one past the end of the buffer, but with that said, it is not needed and the assignment as a whole is incorrect. To perform string interpolation, use a function such as sprintf.
Aside from the fact that you only open the file for writing, the primary problem is that
fwrite(leaderboard, sizeof(char), sizeof(leaderboard), datei);
will write the entire contents of leaderboard to the file. This includes the garbage values that exist towards the end of each array, after each string. fgets will then read those garbage values later.
You should stick to reading and writing binary or text, but do not mix them. If you use fgets, use fputs (or similar) to write the text. Conversely, if you use fwrite, use fread to read the binary data.
Here is a basic, cursory snippet using text functions, where we:
open the file for reading
read our lines into the array
close the file
add our new score to the array
sort our array using qsort
open the file for writing
write our lines
close the file
The trick here is leaderboard has an additional slot, so that there is always room for our newest score. After sorting, we only write at most MAX_ENTRIES entries to the file, meaning if the array is full we ignore the worst score.
#define MAX_ENTRIES 10
#define MAX_LENGTH 300
#define SAVE_FILE "leaderboard.txt"
int compare(const void *ap, const void *bp) {
const char (*a)[MAX_LENGTH] = ap;
const char (*b)[MAX_LENGTH] = bp;
int av, bv;
sscanf(*a, "%d", &av);
sscanf(*b, "%d", &bv);
return (av > bv) - (av < bv);
}
void saveScore(int guess, int randNumber) {
char leaderboard[MAX_ENTRIES + 1][MAX_LENGTH] = { 0 };
size_t entries = 0;
FILE *file = fopen(SAVE_FILE, "r");
if (file) {
while (entries < MAX_ENTRIES &&
fgets(leaderboard[entries], sizeof *leaderboard, file))
entries++;
fclose(file);
}
sprintf(leaderboard[entries], "%d %d\n", guess, randNumber);
entries++;
qsort(leaderboard, entries, sizeof *leaderboard, compare);
file = fopen(SAVE_FILE, "w");
if (file) {
for (size_t i = 0; i < entries && i < MAX_ENTRIES; i++)
fputs(leaderboard[i], file);
fclose(file);
}
}
First Post...
Ive finally upped my game after doing a course in C on Udemy, this is my first application.
Ive created a ToDo list in the command line, with basic functionality, it cannot read the todo list, if you exit the program, the array of strings i created goes back to being empty.
I have made it so a file is saved from the array when the application is exited by pressing 4.
Here is my program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 101
#define MAX_TODO 20
int main() {
int input;
int loop;
FILE *f;
char list[MAX_TODO][MAX_STRING_LENGTH] = {};
while(1){
printf("\n==================== ToDo List ====================\n");
printf("Do not leave the app, keep it running!\n");
printf("You will lose all your todos!\n\n");
printf(" - Please enter a number - \n");
printf("1. See todos \n");
printf("2. Add todo \n");
printf("3. Delete todo \n");
printf("4. Leave\n\n");
scanf("%d", &input);
if(input == 4){
f = fopen("list.bin", "w");
fwrite(list, sizeof(char), sizeof(list), f);
fclose(f);
return EXIT_SUCCESS;
}else if (input == 1 || input == 2 || input == 3){
switch(input){
case 1:
for (int loop = 0; loop < MAX_TODO; loop++)
{
printf("[%2d]. %s\n", loop + 1, list[loop]);
}
break;
case 2:
printf("Please enter the number you would like to replace! ");
int j;
scanf("%d", &j);
getchar();
scanf("%[^\n]", list[j - 1]);
break;
case 3:
printf("Please enter the number you would like to remove! ");
int k;
scanf("%d", &k);
strncpy(list[k-1], " ", 101);
printf("[%d] ---> DELETED!!!", k);
break;
}
}else {
printf("Please enter 1, 2, 3, or 4...\n");
}
}
return EXIT_SUCCESS;
}
Any thoughts on how to implement a read process so that my ToDo list works effectively?
Arrays
#define MAX_LINE_LENGTH 101
#define MAX_LINES 20
char lines[MAX_LINES][MAX_LINE_LENGTH];
int num_lines = 0;
In this case, notice that the variables here are global. Your program is a program with express purpose of maintaining a list of TODO lines: it is OK to make that a global object. Every function of your program works on that data.
Next, break the task down — make some useful functions:
Read a line from file
bool read_line( FILE * f )
{
if (num_lines >= MAX_LINES) return false;
if (!fgets( lines[num_lines], MAX_LINE_LENGTH, f )) return false;
char * p = strptok( lines[num_lines], "\r\n" );
if (!p) return false;
*p = '\0';
num_lines += 1;
return true;
}
In particular, we presume input lines are short enough to fit in our list. If some external process has done something to that it isn’t our fault and we can simply fail.
If you wish you can do things like complain to the user and explain what happened, or even skip to the end of the current line (read characters until you get a newline) and then continue reading lines. However you do it, just document it somewhere for your user.
Write a line to file
void write_line( FILE * f, int n )
{
fprintf( f, "%s\n", lines[n] );
}
Read all lines from file
void read_all_lines( const char * filename )
{
FILE * f = fopen( filename, "r" );
if (!f) return;
while (read_line( f ))
;
fclose( f );
}
It could be argued that the array bounds checking should be done here and the read_line() function should be more general. You could do it that way, of course.
Write all lines to file
void write_all_lines( const char * filename )
{
FILE * f = fopen( filename, "w" );
if (!f) return;
for (int n = 0; n < num_lines; n++)
write_line( f, n );
fclose( f );
}
Use it
int main(void)
{
...
// Load the TODO list
read_all_lines( "TODO.txt" );
...
// Save the TODO list
write_all_lines( "TODO.txt" );
...
}
Further Thought
This is not the only way to do it, nor is it the One True Way™. This is convenient because it is a line-by-line method that does not use extra space on disk: the generated file is a standard textual file that can easily be edited by other programs.
You could, as suggested above, just read and write the entire block:
// Load the lines array from file
fread( lines, MAX_LINES, MAX_LINE_LENGTH, f );
// Save the lines array to file
fwrite( lines, MAX_LINES, MAX_LINE_LENGTH, f );
You could load the entire file as a single string then have an array of pointers into the loaded memory block. I won’t provide an example for that.
I am a fan of the “break your problem down into functions” method of learning to do stuff.
I'm trying to get better at coding in general and C in particular, and am coding a small text adventure game. I read a string input by the user i.e LOOK room and compare it to a txt file with the list of commands for that particular section.
As I am reading from the text file I have a counter which keeps track of which line is being read, when the match is made I convert the line number to a character and concatenate it to "outside.txt" so that when the correct command is input it will read from the correct file i.e LOOK room would load text from 1outside.txt etc.
However, when inputting anything it just loops on "I dont understand" forever. Any explanation as to why or constructive comments on my code are appreciated, especially if I am misunderstanding how files and/or strings in c.
int mansionOutside(void)
{
int stop = 1;
char choice[25];
char word_match[25];
char text_line[73];
char line1[25];
char temp[2];
int counter;
FILE *fptr;
fptr = fopen("mansion_commands.txt", "r");
if (fptr == NULL)
{
printf("ERROR!");
}
else
{
while (stop == 1)
{
printf("\n");
fgets(choice, sizeof choice, stdin);
while (fgets (line1, 25, fptr)!= NULL)
{
if (strcmp(line1, choice) == 0)
{
printf("%s\n", line1);
stop = 0;
break;
}
else
{
counter++;
printf("%s + %s\n", line1, choice);
}
}
if (stop == 1)
{
printf("I dont understand\n");
counter = 1;
}
}
fclose(fptr);
counter = counter + '0';
temp[0] = counter;
temp[1] = '\0';
strncat(word_match, temp , 1);
strcat(word_match, ".txt");
fptr = fopen(word_match, "r");
if (fptr == NULL)
{
printf("ERROR!\n");
}
else
{
printf("Debugging : File opened Successfully\n");
while (fgets (text_line, 72, fptr) != NULL)
{
printf("%s", text_line);
//delay(2);
}
}
}
}
EDIT : Took in suggestions for improvements to avoid Buffer overflows such as using > fgets , but I think there is something I have missed. Now If I input anything contained in the file, it works fine. If however I input something wrong, then something correct on re-prompt, It skips the inner while loop all together and goes straight to "I don't understand".
The following is what happens when my input is LOOK room, and then LOOK mansion.
Glad to ask you again!
I want to create a program that basically reads a file called message.txt which would have some texts with a message, let's say: ''Hello I am a program'' and then encrypts that message and puts it in a file called encryptMessage.txt, additionally it will save the key used for the user in the file key.txt. Now this is what I have done so far. I don't know how to make the program read the file message.txt, show it into the screen and then encrypt it into the file. Any piece of advice? Thank you!
I was planning to use fscanf, but I can't use it because it's a line, not just a single string.
Please, if possible write the code yourself so I can compare it to what I have written so far. I always appreciate your feedback, thanks!
#include <stdio.h>
#include <ctype.h>
#define MAXSIZE 100
int main(void)
{
FILE *message;
FILE *encryptMessage;
FILE *key;
message = fopen("message.txt", "r");
encryptMessage = fopen("encryptMessage.txt", "w");
key = fopen("key.txt", "w");
if ((encryptMessage == NULL) || (encryptMessage == NULL) || (encryptMessage == NULL))
{
printf("Error reading file!!!\n");
return 1;
}
int userKey;
char sentence[MAXSIZE];
char q[MAXSIZE];
int i = 0;
printf("Input the text that you want to encrypt:\n> "); // These two lines are a test to see if I was able to encrypt the message, but this is not necessary. It should directly read the file called message.txt.
fgets(sentence, 99, stdin);
// printf("\nThe string that you wrote is:\n%s\n\n", sentence);
printf("Input the key:\n");
scanf("%d", &userKey);
fprintf(key, "%d", userKey);
//printf("\nThe key that you selected is: %d\n\n", userKey);
for(i = 0; sentence[i] != '\0'; ++i)
{
if( ( isupper(sentence[i]) ) || ( islower(sentence[i]) ) )
{
q[i] = sentence[i] + (char)userKey;
}
else
{
q[i] = (sentence[i]);
}
}
q[i] = '\0';
printf("%s", q);
fprintf(encryptMessage, "%s", q);
fclose(encryptMessage);
return 0;
}
To read a line from message.txt you need to use fgets function.
fgets(sentence, 99, stdin);
The above fgets(which you have in your code) reads from the stdin which is normally the keyboard. To make it read from the text file,use
fgets(sentence, MAX_SIZE, message);
Note the change in the second argument too. If you want to display whatever was scanned,uncomment the below line which you have in your code
//printf("\nThe string that you wrote is:\n%s\n\n", sentence);
Don't forget to close(using fclose) all the FILE pointers which you had opened(using fopen) after its use.
My task is to find word palindromes in a text file and to NOT print them into results file. The results file should only contain all the spaces and words that are NOT palindromes. I've been working on this program for two solid weeks, but as I am a total newb in C, I can't simply imagine how to do this correctly. Also, I have to work in Linux environent, so I can't use commands like strrev() which would make my life a lot easier at this point...
Anyways, data file contains a lot of words in a lot of lines separated by quite a few spaces.
Here is the program that is working, but doesn't work with any spaces, because I don't know how to check them at the needed place.
#include <stdio.h>
#include <string.h>
const int CMAX = 1000;
const int Dydis = 256;
FILE *dataFile;
FILE *resFile;
void palindrome(char *linex);
int main(){
char duom[CMAX], res[CMAX], linex[Dydis];
printf("What's the name of data file? \n");
scanf("%s", duom);
dataFile=fopen(duom, "r");
if (dataFile==NULL){
printf ("Error opening data file \n");
return 0;
};
printf("What's the name of results file? \n");
scanf ("%s", res);
resFile=fopen(res, "w");
if (resFile==NULL){
printf ("Error opening results file \n");
return 0;
};
while (fgets(linex, sizeof(linex), dataFile)) {
palindrome(linex);
}
printf ("all done!");
fclose(dataFile);
fclose(resFile);
}
void palindrome(char *linex){
int i, wordlenght, j;
j = 0;
char *wordie;
const char space[2] = " ";
wordie = strtok(linex, space);
while ( wordie != NULL ) {
wordlenght = strlen(wordie);
if (wordie[j] == wordie[wordlenght-1]) {
for (i = 0; i < strlen(wordie); i++) {
if (wordie[i] == wordie[wordlenght-1]) {
if (i == strlen(wordie)-1) {
fprintf(resFile,"");
}
wordlenght--;
}
else {
fprintf(resFile,"%s", wordie);
break;
}
}
}
else {
fprintf(resFile,"%s", wordie);
}
wordie = strtok(NULL, space);
}
}
EDIT:
Code below works as following:
input file is read char by char
if char read isn't alphanumeric, then it is written to the output file
else, the whole word is read with fscanf
if word is not a palindrome, then write to the output file
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int is_pal(char* word) {
size_t len = strlen(word);
char* begin = word;
char* end = word + len - 1;
if (len == 1) {
return 1;
}
while (begin <= end) {
if (*begin != *end) {
return 0;
}
begin++;
end--;
}
return 1;
}
int main(void)
{
FILE* fin = fopen("pals.txt", "r");
if (fin == NULL) {
perror("fopen");
exit(1);
}
FILE* fout = fopen("out_pals.txt", "w");
if (fout == NULL) {
perror("fopen");
exit(1);
}
int ret;
char word[100];
while ((ret = fgetc(fin)) != EOF) {
if (!isalpha(ret)) {
fprintf(fout, "%c", ret);
}
else {
ungetc(ret, fin);
fscanf(fin, "%s", word);
if (!is_pal(word)) {
fprintf(fout, "%s", word);
}
}
}
fclose(fin);
fclose(fout);
return 0;
}
I've created file with following content:
cancer kajak anna sam truck
test1 abc abdcgf groove void
xyz annabelle ponton belowoleb thing
cooc ringnir
The output file :
cancer sam truck
test1 abc abdcgf groove void
xyz annabelle ponton thing
(line with two spaces)
As you can see, the number of spaces between words are the same as in the input file.
I've assumed that single word could have 100 chars maximum. If there would be longer words, reading with fscanf onto fixed-size buffer can be harmful.
Hints:
strtok() gives you a pointer to the start of delimited words but it does not
extract them or put them in their own string for you.
You need some logic to find the end of each word. The function
strlen() will tell you how many characters there are from the char*
that it gets until a null-character. If you give it a pointer to the start
of a word within a sentence it will give you the length from the start of the
word to the end of the sentence.
Breaking palindrome() into a function that loops over words in a line and a
function that returns whether or not a single word is a palindrome
may help.
Your for loop is checking each pair of letters twice. i only needs to scan over half
of the word length.
You only need a single if within palindrome(). I'm not sure why you have so many.
They're redundant.