2

I would like to get the last character in file using the following code

 FILE * f = fopen ( f_text, "r" );
 if (f )
 {
    if (fseek( f, -1, SEEK_END ) != 0 ) fclose (f);
    char last[1]; 
    fgets(last, 1, f );
    ...

but only "" is stored in variable last. Where is the bug?

Is there any problem with unicode files? Thanks for your help.

justik
  • 4,145
  • 6
  • 32
  • 53
  • 1
    If it is a proper text file, wouldn't the last character be `\n`? – jxh Jul 05 '12 at 17:21
  • This code does not compile, because you are missing a `)` before `fclose(f);` – Rontogiannis Aristofanis Jul 05 '12 at 17:27
  • @user315052: No, why should that be the case? – Benjamin Lindley Jul 05 '12 at 17:46
  • @BenjaminLindley: It can be an indication of an inadvertently truncated text file. For example, your text editor crashed. – jxh Jul 05 '12 at 17:56
  • @user315052: It can be, but one is perfectly capable of saving a text file without a trailing new line character. – Benjamin Lindley Jul 05 '12 at 18:02
  • @BenjaminLindley: A text file is by definition line oriented data. It [would cause problems when working with text file tools](http://stackoverflow.com/questions/729692/why-should-files-end-with-a-newline) if the last line did not look like all the other lines. – jxh Jul 05 '12 at 18:10
  • @user315052 If it's a proper text file, the `fseek` is illegal. (I forget whether it is undefined behavior, or the function should return an error. The former, I suspect, so that implementations under Unix can make it work.) – James Kanze Jul 05 '12 at 18:26
  • @BenjaminLindley If the last character output to a file opened in text mode is not a `'\n'`, the program has undefined behavior. – James Kanze Jul 05 '12 at 18:29
  • @JamesKanze: You're right, I'll update my answer. – jxh Jul 05 '12 at 18:40

3 Answers3

4

The problem is that fgets will form a string. Since you only gave it one byte to work with, it can only return you an empty string, since it needs that byte to store the '\0'.

As James Kanze pointed out to me, you can only use fseek the way you want portably if you have opened the file in binary mode. Since the file is now in binary mode, it would be inappropriate to use fgets. So you would use fread instead.

FILE *f = fopen(f_text, "rb");
if (f == 0) throw 0;
try {
    if (fseek(f, -1, SEEK_END) != 0) throw 0;
    char last[1];
    if (fread(last, 1, 1, f) != 1) throw 0;
    //...
}
catch (...) {
    fclose(f);
    throw;
}
fclose(f);
jxh
  • 69,070
  • 8
  • 110
  • 193
1

Try using fgetc instead of fgets

nav_jan
  • 2,473
  • 4
  • 24
  • 42
0

I made some changes to your code to print the last character. Here is test.c as a sample:

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

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

    FILE * f;
    char * f_text = "temp.txt";

    f = fopen ( f_text, "r" );
    if (f )
    {

        if (fseek( f, -2, SEEK_END ) == 0 ) 
        {
            char last[2] = {0}; 
            printf("Got here.\n");
            last[0] = fgetc( f );
            printf("%s\n", last);
        }
    }

    return 0;
}

and here is temp.txt displayed at the command line.

octopusgrabbus@steamboy:~/scratch$ cat temp.txt
This is a test.
octopusgrabbus@steamboy:~/scratch$ 

I changed your fseek to seek two from the end, so test would print the period. As another answer indicated, I used fgetc instead of fgets, because you were looking for an individual character, not a full string.

I also changed last to last[2] and initialized to zero, so I could treat the last character as a zero-terminated string for demo purposes.

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131