1

The goal is to fill file output.txt with characters that are repeating one after another n or more times (n is an integer inputted from a keyboard).

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

int main() {
    int c=0,d=0;
    int n;
    scanf("%d",&n);
    FILE* ulaz=fopen("input.txt","r");
    if(ulaz==NULL) {
        printf("TRY AGAIN");
        return 1;
    }
    FILE* izlaz=fopen("output.txt","w");
    if(izlaz==NULL) {
        fclose(ulaz);
        printf("TRY AGAIN");
        return 2;
    }
    long pos;
    int br=1;
    do {
        c=fgetc(ulaz);
            if(c!=EOF) {
            do {
                long pos=ftell(ulaz);
                d=fgetc(ulaz);
                if(c==d) {
                    br++;
                }
            } while(d==c && d!=EOF);
            int i=0;
            if(br>=n) {
                for(i=0;i<n;i++) {
                    fputc(c,izlaz);
                }
            }
            fseek(ulaz,pos,SEEK_SET);
            //is this line a problem
            br=1; }
    } while(c!=EOF);
    fclose(ulaz);
    fclose(izlaz);
}
3
  • 2
    Note that your do { c = fgetc(ulaz); if (c != EOF) { … } } while (c != EOF); loop could be written more succinctly and idiomatically as while ((c = fgetc(ulaz)) != EOF) { … }. Commented Feb 9, 2019 at 23:13
  • If you are using gcc/clang, add -Wshadow to your compiler string to catch variable shadowing as occurred here. I'll have to check, but /W3 on VS should catch the same. Commented Feb 10, 2019 at 7:30
  • in C, as with most programming languages, functions can fail, including C library functions. for robust code, always check for error indications Commented Feb 10, 2019 at 20:42

2 Answers 2

1

It's because you write long pos=ftell(ulaz); instead of pos=ftell(ulaz);. In the block of the do, where you define a new variable long pos= ..., you are covering the outer pos-variable that you use later for resetting the position to the value you stored.

Maybe there are other problems as well, but this is the most obvious one in conjunction with your "//is this line a problem".

Sign up to request clarification or add additional context in comments.

Comments

0

In addition to the variable shadowing issue noted by @StephanLechner, you are over-complicating the recognition and outputting of repeated characters in your input file. There is no need for nested loops within your read loop (other than to output repeated characters), and no reason to ftell or fseek.

Take a State-Loop Approach

Any time you are handling a problem such as a repeated character count (or whitespace removal, etc..) all you need to do it loop over each character of input and maintain the current "state" of whether you are reading a repeated character and handle any change o state by using conditionals within your loop (commonly termed a "state-loop" approach)

In your case, you need only maintain (1) the previous character read to determine if the current is a repeat, and (2) the repeat count. You then have only 2 possible states to handle, (1) the current character is a repeat of the last, or (2) it isn't.

After opening and validating your input and output files are ready reading and writing, you can handle the duplicate detection and out similar to the following:

    int c, last = 0;            /* current and last char read */
    size_t repeated, cnt = 1;   /* min repeated and repeat count */
    FILE *ulaz, *izlaz;         /* file pointers */
    ...
    while ((c = fgetc (ulaz)) != EOF) {     /* read each char */
        if (c == last)                      /* if equals last read */
            cnt++;                          /* increment count */
        else {  /* otherwise */
            if (cnt >= repeated)            /* if count >= min */
                while (cnt--)               /* loop count times */
                    fputc (last, izlaz);    /* writing last to out */
            cnt = 1;                        /* reset count */
        }
        last = c;   /* save c as last */
    }

The flow of the loop is simple. You read a characters from input, check if it is a repeated character or not, and save the current character as last.

How do you respond to each state?

In the case the character is a repeated character, you simply increment the repeat count (always initialized 1 -- when a repeat is found, it will be the 2nd occurrence of the letter). If the character isn't a repeat, then you have to check whether the accumulated repeat count equals or exceeds the minimum you are testing for, and if so, output that number of last characters to your output file -- always resetting the count to 1. That's it. A state-loop approach can simplify many similar type problems.

The remainder is just reading your minimum limit[1] as user input and closing your files when you are done. One note there, you should always validate the close after a write to protect against stream errors that cannot be caught by validating the write itself. fclose returning EOF will identify such errors and errno is set accordingly.

Putting it altogether, you could do:

#include <stdio.h>

int main (int argc, char **argv) {

    int c, last = 0;            /* current and last char read */
    size_t repeated, cnt = 1;   /* min repeated and repeat count */
    FILE *ulaz, *izlaz;         /* file pointers */

    if (argc < 3 ) {    /* validate at least two arguments given */
        fprintf (stderr, "error: insufficient input,\n"
                    "usage: %s infile outfile\n", argv[0]);
        return 1;
    }

    /* validate input and output files are open */
    if (!(ulaz = fopen (argv[1], "r")) || !(izlaz = fopen (argv[2], "w"))) {
        perror ("fopen-file");
        return 1;
    }

    /* prompt, read, validate minimum repeatee input */
    fputs ("enter the minimum repeat: ", stdout);
    if (scanf ("%zu", &repeated) != 1) {
        fputs ("error: invalid input.\n", stderr);
        return 1;
    }

    while ((c = fgetc (ulaz)) != EOF) {     /* read each char */
        if (c == last)                      /* if equals last read */
            cnt++;                          /* increment count */
        else {  /* otherwise */
            if (cnt >= repeated)            /* if count >= min */
                while (cnt--)               /* loop count times */
                    fputc (last, izlaz);    /* writing last to out */
            cnt = 1;                        /* reset count */
        }
        last = c;   /* save c as last */
    }
    fputc ('\n', izlaz);            /* tidy up with POSIX '\n' */

    fclose (ulaz);                  /* close input */
    if (fclose (izlaz) == EOF)      /* validate close after write */
        perror ("fclose-izlaz");

    return 0;
}

(note: you should always make sure your output is POSIX compliant including a '\n' after the final line in the output -- that applies whether you are writing an output file or to the terminal -- nobody likes having their prompt messed up)

Example Input File

$ cat dat/repeat.txt
abbc dddde fgggh ijkllllmmmn oopqrs

Example Use/Output Files

With a 2-character minimum:

$ ./bin/repeated_ulaz dat/repeat.txt dat/repeated_out-2.txt
enter the minimum repeat: 2

$ cat dat/repeated_out-2.txt
bbddddgggllllmmmoo

With a 3-character minimum:

$ ./bin/repeated_ulaz dat/repeat.txt dat/repeated_out-3.txt
enter the minimum repeat: 3

$ cat dat/repeated_out-3.txt
ddddgggllllmmm

With a 4-character minimum:

$ ./bin/repeated_ulaz dat/repeat.txt dat/repeated_out-4.txt
enter the minimum repeat: 4

$ cat dat/repeated_out-4.txt
ddddllll

Look things over and let me know if you have further questions.

Footnotes

[1] if you are using an old version of the VS compiler that doesn't handle the size_t "%zu" format specifier, change all size_t to unsigned and change all "%zu" to "%u".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.