Ansdai
Ansdai

Reputation: 47

read() system call reads in an extra 0

I wrote a function that uses read() system call to read numbers from a file and put them into an array. However, I've noticed that there is always an extra 0 included at the end.

       int numberRead = 0;
       int fp;
       char buf[512];
       size_t nbytes = sizeof(buf);
       int n;
       int counter = 0;
       char* ptr;
       size_t curSize = 16;
       int radix = hexFlag ? 16 : 10;


        *array = malloc(curSize * sizeof(*array));

        fp = open(fname, O_RDONLY);      

            if (fp == -1) {
                    return -1;
            }

        while ((n = read(fp, buf, nbytes)) != 0) {
            ptr = strtok(buf, " \n");
            while(ptr) {
                if (counter >= curSize) {
                    curSize += 16;
                    *array = realloc(*array, curSize * sizeof(**array));
                }
                (*array)[counter++] = strtol(ptr, NULL, radix);
                ++numberRead;
                ptr = strtok(NULL , " \n");
            }
        }

Is the reason due to strtok?

Upvotes: 1

Views: 1651

Answers (1)

Chris Dodd
Chris Dodd

Reputation: 126243

read does not NULL-terminate the buffer it reads into, so this code will likely get an extra number after the end of the last read, which was hanging around in the buffer from the previous read. Add the line:

buf[n] = 0;

immediately after the first while line that calls read.

In addition, the blocks read by read don't necessarily correspond to lines or anything else in particular. If you're reading from a file, a read call might might return a block of characters that ends in the middle of a multi-digit number, in which case your code will split it into two numbers. In order to avoid this, you need to not try to tokenize/decode the last few characters read (everything after the last whitespace read), and instead prepend them to the next read.

You end up needing code something like:

char buf[1024], *end;
size_t n;
size_t leftover = 0;
while ((n = read(fp, buf+leftover, sizeof(buf)-leftover-1)) > 0 || leftover > 0) {
    buf[leftover+n] = 0;
    ptr = strtok(buf, " \n");
    while(ptr) {
        if (counter >= curSize) {
            curSize += 16;
            *array = realloc(*array, curSize * sizeof(**array));
        }
        (*array)[counter] = strtol(ptr, &end, radix);
        if (end == buf+leftover+n && n > 0) {
            leftover = ptr-end;
            memmove(buf, ptr, leftover);
            break; }
        ++counter;
        ++numberRead;
        ptr = strtok(NULL , " \n");
    }
    if (!ptr) leftover = 0;
}

Upvotes: 5

Related Questions