0

I want to write simple encrypt text system that is read from in.txt then write to out.txt Encryption type is every ascii plus five if char btw u and z , u=a,v=b,......,z=f where is my problem? Besides, can we do using modulos operator(%) instead of (char-20) if char btw u and z , u=a,v=b,......,z=f where is my problem? my code is below thank you all appreciated answers. text is in in.txt that test abcde

#include <stdio.h>


int main(){

        char ch;
        int st;

        FILE *fptr_in;
        FILE *fptr_out;

        fptr_in=fopen("in.txt","r");
        fptr_out=fopen("out.txt","w");
        if(fptr_in== NULL || fptr_out==NULL)
                    printf("File cannot be opened\n");
        else{
            st=(fscanf(fptr_in,"%c",&ch));
                while(st==1){
           /* for(st=(fscanf(fptr_in,"%c",&ch));
                st==1;
                st=(fscanf(fptr_in,"%c",&ch)))*/

                        st=(fscanf(fptr_in,"%c",&ch));

            if('a'<=ch && ch<='z'){
                fscanf(fptr_in,"%c",&ch);
            if(ch==' ')
                fprintf(fptr_out, "%c", ' ');
            else if('u'<=ch && ch<='z')
                fprintf(fptr_out, "%c", (char)((int)ch-20));
            else
            fprintf(fptr_out, "%c", (char)((int)ch+5));
            }
    }

}
        fclose(fptr_in);
            fclose(fptr_out);

        return 0;
}
  • That kind of cipher is called [Caesar cipher](http://stackoverflow.com/search?q=caesar+cipher) for which there are already many answers on SO. Also, please check the return value of `fscanf` instead of testing `feof`. [Here's why](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong). – M Oehm Oct 08 '14 at 17:19
  • `if('a'<=ch && ch<='z'){ fscanf(fptr_in,"%c",&ch);` wrong. – BLUEPIXY Oct 08 '14 at 17:22
  • bluepixy why ? thank you m oehm i edited –  Oct 08 '14 at 17:28

1 Answers1

0

Some comments on your code:

  • It's good that you check the file pointers after calling fopen, but you should exit the program if you can't open them. Otherwise, the while loop is entered and fscan calles on a null pointer. You can use exit(1) from <stdlib.h>. (This is almost like returning 1 from main, but can be called from everywhere.)
  • fscanf(f, "%c", &ch) is better rendered as ch = getc(f). Likewise fprintf(f, "%c", ch) can be written more succinctly as putc(ch, f). (Your variants aren't wrog, but needlessly wordy, in my opinion.)
  • Your cipher code has three cases: Space, letters u to z, and everything else. That means that you also shift punctuation and special characters like newline. You should probably use the three cases uppercase letter, lowercase letter and everything else.

Below's a working implementation. Things to note:

  • I use getc, which requires ch to be an int.
  • Reading the chars from in.txt is done in an infiinite loop with for(;;). The loop ends with the break statement when EOF is read. (Ii is usually better to have loops with proper conditions, but in this case I prefer the break, because it allows me to make ch local to this loop and also doesn't need assignments in conditions, which I find ugly.
  • The Caesar cipher is implemented as a separate function, to which the shift is passed. It encodes uppercase and lowercase letters by using the modulo function you suggested. This requires a positive shift.
  • Note that both the I/O loop and the cipher function are quite short, which is nice.

Here's the example:

#include <stdlib.h>
#include <stdio.h>

#define INFILE "in.txt"
#define OUTFILE "out.txt"

int caesar(int ch, int shift)
{
    while (shift < 0) shift += 26;
    if ('a' <= ch && ch <= 'z') return ('a' + (ch - 'a' + shift) % 26);
    if ('A' <= ch && ch <= 'Z') return ('A' + (ch - 'A' + shift) % 26);
    return ch;
}

int main()
{
    FILE *fptr_in;
    FILE *fptr_out;

    fptr_in = fopen(INFILE, "r");
    if (fptr_in == NULL) {
        fprintf(stderr, "Can't open %s.\n", INFILE);
        exit(1);
    }

    fptr_out = fopen(OUTFILE, "w");
    if (fptr_in == NULL) {
        fprintf(stderr, "Can't create %s.\n", OUTFILE);
        exit(1);
    }

    for (;;) {
        int ch = getc(fptr_in);

        if (ch == EOF) break;
        putc(caesar(ch, 5), fptr_out);
    }

    fclose(fptr_in);
    fclose(fptr_out);

    return 0;
}
M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • that's very good :) however i wonder where my wrong is in my code –  Oct 08 '14 at 17:59
  • also why modulo %26 ? –  Oct 08 '14 at 18:24
  • @Soner: I've tried to address some "issues" with your code in the answer. I think the main problem is in how you read the data. For example, there should only be one `fscanf` (or `getc`) in the loop, but you have a second one where you read the next character when the current one is a letter, which doesn't make sense. If you want to correct your code, I suggest that you write a program to copy all chars from in.txt to out.txt verbatim. When that works, add the encryption. – M Oehm Oct 08 '14 at 18:33
  • @Soner: Why 26? There are 26 letters in the Latin alphabet. The expression `'a'` gives me the ASCII code of a small a. The expression `ch - 'a'` yields the ordinal number of a letter in the alphabet: 0 for a, 1 for b, 25 for z. Add the (positive) shift. Then calculate the modulo, so that letters that go beyond z are wrapped back to the beginning: z + 5 is 25 + 5 is 30. 30 modulo 26 is 4, which yields an e. – M Oehm Oct 08 '14 at 18:37