How to offset in fseek from current position

351 views Asked by At

I somehow cannot ofset from SEEK_CUR:

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

int main()
{
    FILE * fp = fopen("txt", "w+b");
    if(!fp)
        return 1;
    
    fprintf(fp, "20");
    fseek(fp, 1, SEEK_CUR);
    fprintf(fp, "19");

    long size = ftell(fp) + 1;
    rewind(fp);
    char * buf = malloc(size+1);
    buf = memset(buf, 0, size+1); //should I really do this? becuase, after the "20" there will be \0 so I won't see the rest (` 19`)
    fread(buf, sizeof(char), size, fp);
    printf("%s\n",buf);

}

output:

20

but should be 20 19, which I cannot fread() from that file, why?

2

There are 2 answers

3
ndim On BEST ANSWER

So you write "20" to the file, then skip one byte/character ahead in the file, then write "19" to the file. The skipped character needs to be written as some value... and that value is \0.

So you read "20\019" from the file into a buf initialized to seven \0 bytes by the memset call. buf now contains "20\019\0\0".

printf("%s\n", buf) prints buf as a NUL terminated string, i.e. until the first NUL byte appears. That NUL byte comes immediately after the "20", so it only prints "20".

If you were to hexdump the buffer with a hexdump function (to be written as an exercise)

hexdump(buf, size);

it would print something like

0000  32 30 00 31 39 00      -                     20.19.
1
Kaz On

The problem is that your buf is not null-terminated. The array is exactly sized to hold the content of the text file, without any null termination.

Try

char buf[size+1] = "";   /* initialize buf to all zeros, with room for null terminator */

A string literal object is already null-terminated, so for most purposes, this is superfluous:

char *str = "abc\0";

The string is now terminated by two nulls, which could be useful in some special circumstances. Microsoft came up with a data format used in the Windows Registry for storing a list of strings. Each string in the list is null-terminated, and then one more null byte unambiguously terminates the entire list. We could declare such a thing in C as:

char *windows_reg_style_list = "how\0now\0brown\cow\0";

To ordinary string processing in C, "abc\0" looks the same as "abc": it's as string of length 3, and likewise the above datum looks like the string "how".

There is, I think, only one situation in which the "..." notation in C source code will not produce a null terminated string. And that is when it is used as the initializer for an array which is exactly sized for that number of characters:

char no_null_term[4] = "abcd";

If we make it [5] it will be null terminated, and [3] would be erroneous since the array is too small to hold abcd. The [4] is allowed as a special case for initializing arrays that don't behave like null-terminated strings.

Also note that to use ftell, the stream has to be binary: fopen(..., "w+b"). So that is to say, ftell is not required to return a value that corresponds to the number of characters written to the text stream.