Reputation: 47
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
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