tags:

views:

101

answers:

3

I'm at a loss debugging this code. I copied the example from a guide, is this file being improperly indexed?

#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

char *inicio(void);

main(void)
{
  char *c;
  int fd, sz, i;    
  c = inicio();

  fd = open("input.in", O_RDONLY);
  if (fd < 0) { perror("r1"); exit(1); }

  sz = read(fd, c, 10);
  printf("We have opened input.in, and have called read(%d, c, 10).\n", fd);
  printf("read has read %d bytes.\n", sz);
  printf("The bytes are these: %s\n", c);

  i = lseek(fd, 0, SEEK_CUR);
  printf("lseek(%d, 0, SEEK_CUR) returns the current location on the file being %d\n\n", fd, i);

  printf("We now look for the start of the file and call read(%d, c, 10)\n",fd);
  lseek(fd, 0, SEEK_SET);
  sz = read(fd, c, 10);

  printf("The reading returns the following bytes: %s\n", c);

  printf("We now execute lseek(%d, -6, SEEK_END). and return %d\n",fd, (int) lseek(fd, -6, SEEK_END));
  printf("Executing read(%d, c, 10), we get the following bytes: ", fd);

  sz = read(fd, c, 10);

  printf("Finally, we execute lseek(%d, -1, SEEK_SET).  This returns -1.\n", fd);
  printf("perror() indicates the fault:\n");
  fflush(stdout);

  i = lseek(fd, -1, SEEK_SET);
  perror("l1");
}

char *inicio(void)
{
  char *bytes;
  int j;
  bytes = (char *) calloc(100, sizeof(char));
  for(j=0;j<100;j++){bytes[j]=rand()%32+1;}
  return bytes;
}

the input file is:

 Jim Plank
 Claxton 221
+1  A: 

printf("The bytes are these: %s\n", c);

Access violation (guaranteed one). You don't have a '\0' terminator.

Same goes for:

printf("The reading returns the following bytes: %s\n", c);

Let_Me_Be
Where should the terminator be placed? On the read file? I'm not used to C and its memory errors.
omgzor
`c[sz] = '\0';` after the read calls.
sharth
This is a valid problem with the code - it is not an explanation for why the last `lseek()` fails.
Jonathan Leffler
@Jonathan Cause it can never be reached?
Let_Me_Be
@omgzor First, don't initialize the array with values 1..32 but zeroes (using `memset()`) and when you are done reading reset the whole array back to zero (using `memset()`).
Let_Me_Be
I added c[sz] = '\0'; after each read call and got the same error :/
omgzor
I'm not convinced; have you tried it? There's likely to be a zero byte in range before too much reading out of bounds occurs. Not guaranteed - but likely. Granted, the printed data is a mess; that is not in dispute (nor am I disputing that it is a genuine problem that you've identified). But, there is nothing here that explains why the last `lseek()` is returning an error.
Jonathan Leffler
Sorry, but I'm a C n00b here. How should the call to memset be specified?
omgzor
@omgzor http://www.cplusplus.com/reference/clibrary/cstring/memset/
Let_Me_Be
@Let_Me_Be: C++ reference for a C function that should probably rarely/never be used in C++? How about this instead: http://www.opengroup.org/onlinepubs/9699919799/functions/memset.html
R..
@R Yes I rather post a C++ reference material, that includes examples than a link to man.
Let_Me_Be
+1  A: 

What exactly do you expect at the -1th position of the file? Maybe you wanted SEEK_CUR or SEEK_END instead of SEEK_SET.

ammoQ
+2  A: 

If you seek to a negative offset from the start of the file, you get an error - there are no accessible bytes before the beginning of the file.

Also, you should always check or capture the results of system calls, rather than relying on errno being set. The C library never sets errno to zero (other than when the process/thread starts). It can be set to a non-zero value even if the function succeeded. On Solaris, it is routine for errno to be set after writing to a file because the file is not a terminal and the library attempts an operation that only succeeds on a terminal.


Working code, minus memory allocation via 'malloc()'. It explicitly prints only the number of characters read ('<<%.*s>>' limits the length to the size given; the angle brackets make it easy to see the data that is being printed).

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char c[100];
    int fd, sz, i;

    fd = open("input.in", O_RDONLY);
    if (fd < 0)
    {
         perror("Error from open(\"input.in\", O_RDONLY)");
         exit(1);
     }

    sz = read(fd, c, 10);
    printf("Opened input.in (fd = %d)\n", fd);
    printf("We called read(fd, c, 10) and read %d bytes: <<%.*s>>\n",
           sz, sz, c);

    i = lseek(fd, 0, SEEK_CUR);
    printf("lseek(fd, 0, SEEK_CUR) returns the current offset of %d\n", i);

    printf("We seek to start of the file and call read(fd, c, 10)\n");
    i = lseek(fd, 0, SEEK_SET);
    if (i != 0)
        perror("Error from lseek(fd, 0, SEEK_SET)\n");

    sz = read(fd, c, 10);
    if (sz < 0)
        perror("Error from read(fd, c, 10)\n");
    printf("We read the following bytes: <<%.*s>>\n", sz, c);

    printf("We now execute lseek(fd, -6, SEEK_END) which returns %d\n", 
           (int) lseek(fd, -6, SEEK_END));
    printf("Executing read(fd, c, 10), we get the following bytes: ");

    sz = read(fd, c, 10);
    if (sz < 0)
        perror("Error from read(fd, c, 10)\n");
    printf("<<%.*s>>\n", sz, c);

    printf("Finally, we execute lseek(fd, -1, SEEK_SET) which returns -1\n");
    fflush(stdout);

    if ((i = lseek(fd, -1, SEEK_SET)) < 0)
        perror("Error from lseek(fd, -1, SEEK_SET)");
    printf("i = %d\n", i);
    return 0;
}

Output:

Opened input.in (fd = 3)
We called read(fd, c, 10) and read 10 bytes: <<Jim Plank
>>
lseek(fd, 0, SEEK_CUR) returns the current offset of 10
We seek to start of the file and call read(fd, c, 10)
We read the following bytes: <<Jim Plank
>>
We now execute lseek(fd, -6, SEEK_END) which returns 16
Executing read(fd, c, 10), we get the following bytes: <<n 221
>>
Finally, we execute lseek(fd, -1, SEEK_SET) which returns -1
Error from lseek(fd, -1, SEEK_SET): Invalid argument
i = -1
Jonathan Leffler
I copied this offset from a guide. I changed each negative for a positive and got a Segmentation Fault, what's the proper way to index here?
omgzor
@omgzor: I'm not sure what you mean - you can't change the signs on everything and expect it to work. Seeking 6 beyond the end of a readonly file is not usually going to help very much, for example. I've updated the answer with non-crashing code.
Jonathan Leffler
Sorry, I was misunderstanding the use of the offset. I changed the last lseek to i = lseek(fd, 0, SEEK_SET) based on your answer and got what I wanted. Thanks.
omgzor