1
votes

I'm working on a project, and I can't seem to figure out why a piece of my function for finding prime numbers won't run. Essentially, I want to code to first check the text file log for any previously encountered prime numbers, but no matter what I put for the while-loop containing fscanf(), it seems like my code never enters it.

int filePrime(int a) {
int hold = 0;
FILE *fp = fopen("primes.txt", "a+");

if (fp == NULL) {
    printf("Error while opening file.");
    exit(2);
}

/*
the while loop below this block is the one with the issue.
on first run, it should skip this loop entirely, and proceed
to finding prime numbers the old-fashioned way, while populating the file.
instead, it is skipping this loop and proceeding right into generating a
new set of prime numbers and writing them to the file, even if the previous
numbers are already in the file
*/

while (fscanf(fp, "%d", &hold) == 1){ 
    printf("Inside scan loop.");
    if (hold >= a) {
        fclose(fp);
        return 1;
    }
    if (a % hold == 0) {
        fclose(fp);
        return 0;
    }
}

printf("Between scan and print.\n");

for (; hold <= a; hold++) {
    if (isPrime(hold) == 1) {
        printf("Printing %d to file\n", hold);
        fprintf(fp, "%d\n", hold);
        if (hold == a)
            return 1;
    }
}

fclose(fp);
return 0;
}

I have tried all sorts of changes to the while-loop test.
Ex. != 0, != EOF, cutting off the == 1 entirely.

I just can't seem to get my code to enter the loop using fscanf.

Any help is very much appreciated, thank you so much for your time.

1
Is there any data in primes.txt? Is the first 'field' a number? Are you sure? Consider using fgets() to read a line — so you can print it, and then scan it with sscanf() instead of fscanf(). - Jonathan Leffler
prime.txt is either a brand new file, created by fopen(), or filled with integers from the fprintf() further down the code. I also tried running it seeded with the initial prime "2", but nothing changed. - ConCat
if (hold == a) return 1; does not first close fp. - chux - Reinstate Monica
why not look see what fscanf is returning. - pm100
Where does the "a+" mode leave the current file pointer? At the start or at the end of the file? If you do an fseek(fp, 0L, SEEK_SET) before the fscanf() loop, does that change anything? - Jonathan Leffler

1 Answers

3
votes

In a comment, I asked where the "a+" mode leaves the current position?

On Mac OS X 10.11.4, using "a+" mode opens the file and positions the read/write position at the end of file.

Demo code (aplus.c):

#include <stdio.h>

int main(void)
{
    const char source[] = "aplus.c";
    FILE *fp = fopen(source, "a+");
    if (fp == NULL)
    {
        fprintf(stderr, "Failed to open file %s\n", source);
    }
    else
    {
        int n;
        char buffer[128];
        fseek(fp, 0L, SEEK_SET);
        while ((n = fscanf(fp, "%127s", buffer)) == 1)
            printf("[%s]\n", buffer);
        printf("n = %d\n", n);
        fclose(fp);
    }
    return(0);
}

Without the fseek(), the return value from n is -1 (EOF) immediately. With the fseek(), the data (source code) can be read.

One thing slightly puzzles me: I can't find information in the POSIX fopen() specification (or in the C standard) which mentions the read/write position after opening a file with "a+" mode. It's clear that write operations will always be at the end, regardless of intervening uses of fseek().

POSIX stipulates that the call to open() shall use O_RDWR|O_CREAT|O_APPEND for "a+", and open() specifies:

The file offset used to mark the current position within the file shall be set to the beginning of the file.

However, as chux notes (thanks!), the C standard explicitly says:

Annex J Portability issues

J.3 Implementation-defined behaviour

J.3.12 Library functions


Whether the file position indicator of an append-mode stream is initially positioned at the beginning or end of the file (7.21.3).

So the behaviour seen is permissible in the C standard.

The manual page on Mac OS X for fopen() says:

  • "a+" — Open for reading and writing. The file is created if it does not exist. The stream is positioned at the end of the file. Subsequent writes to the file will always end up at the then current end of file, irrespective of any intervening fseek(3) or similar.

This is allowed by Standard C; it isn't clear it is fully POSIX-compliant.