1

I'm trying to read a file line by line using fgets, but its not working. Here is my code:

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

#define MAX_LINE_SIZE 500
int main(int argc, char const *argv[])
{
    char *line;
    FILE *arq;


    //abre o arquivo para leitura
    if ((arq = fopen (argv[1], "r")) == NULL){
            printf ("erro ao abrir arquivo\n");
            exit (1);
    } 

    //aloca espaco para a linha
    if ((line = (char*) calloc (MAX_LINE_SIZE, sizeof(char))) == NULL){
            printf ("erro ao alocar memoria\n");
            exit (1);
    }

    //para cada linha
    while (fgets (line, MAX_LINE_SIZE, arq) != NULL){
            printf ("%s\n", line);
    }

    //desaloca a memoria
    free (line);

    //fecha o arquivo
    fclose (arq);

    return 0;
}

If my input file has the first line shorter than the size specified in the MAX_LINE_SIZE, in the same interaction, the fgets starts to overwrite the content of the first line with the content of the second line. For example, using MAX_LINE_SIZE = 14 with this input text:

AAAAAAA 
BBBBBBBBBB

I get this output:

Gabriels-MacBook-Air:Desktop Gabriel$ make
gcc teste.c;./a.out input.txt
BBBBBAA
BBBBB

I think the fgets method is recognizing the break line character, then, it moves the writing pointer to the beggining of the string and continues to read until the MAX_INE_SIZE is reached. But, why? Can somebody help me? Thanks!

ryanpattison
  • 6,151
  • 1
  • 21
  • 28
Gabriel Bessa
  • 468
  • 1
  • 4
  • 8
  • 1
    But your example *does not* have the input line shorter than 14. When I compile & run that, I get the output `"AAAAAAA BBBBB[newline]BBBBB"` as expected. – Weather Vane Jun 04 '15 at 19:32
  • Yeah, the output is the expected one here too. – RenatoUtsch Jun 04 '15 at 19:33
  • Please post compilable code. The code you pasted does not compile. Particularly show how you define `MAX_LINE_SIZE`. – Alex Reynolds Jun 04 '15 at 19:34
  • Also: Do not cast `malloc`, `calloc` or `realloc` calls as this can hide errors. – Alex Reynolds Jun 04 '15 at 19:37
  • 2
    @RenatoUtsch (from deleted answer) nothing *wrong* with it, but it's one of the most frequently argued points here. I'm with the **don't cast `malloc` in C** camp. http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Weather Vane Jun 04 '15 at 19:39
  • 2
    can you look at the input file with a hex editor? Possibly there is a CR or LF after the A's. – wimh Jun 04 '15 at 19:42
  • @WeatherVane I see. Good to know about these other reasons. – RenatoUtsch Jun 04 '15 at 19:45

2 Answers2

0

Maybe your file has line-endings that don't match your platform? If your file is using CR as the line ending (old MacOS) and you run this on Unix-like platforms, you'd get this behavior.

Ewan Mellor
  • 6,747
  • 1
  • 24
  • 39
  • 1
    Not really, with a buffer size of 14 `fgets` wouldn't even get to the end of the line. Even with a bigger buffer, why wouldn't everything be printed? – RenatoUtsch Jun 04 '15 at 19:40
  • @EwanMellor I wondered about that, but the `printf` includes the `\n` newline, so unless that is misbehaving too... – Weather Vane Jun 04 '15 at 19:41
  • This seems to be the correct answer, and I reproduced the exact behaviour with a Carriage-Return (0x0D) between the "A"s and the "B"s. – The first fgets() reads "AAAAAABBBBB", which, when printed to the Terminal, looks like "BBBBBAA". – Martin R Jun 04 '15 at 19:43
  • So is OP's example incorrectly rendered here? Is that supposed to be two lines with `0x0D` where the `space` is? In that case, it is read as part of the 14 chars, prints a `return` instead of a `newline`, stops at the 14 length, **now** prints a `newline`, to get the given answer. Upvoted. – Weather Vane Jun 04 '15 at 19:47
  • Thx! The problem was in the file. I've created a new one and now everything is ok. – Gabriel Bessa Jun 04 '15 at 19:48
  • I put in a similar line ending with `unix2dos`, verified with `hexdump`, and could not reproduce the reported error. – Alex Reynolds Jun 04 '15 at 19:48
  • @AlexReynolds put the `0x0D` where the `space` is. The example then becomes consistent with OP's statement that the first line is < 14 chars length. – Weather Vane Jun 04 '15 at 19:49
  • The markdown for quotes in the question renders the newline as a space. – ryanpattison Jun 04 '15 at 19:52
  • Note: before the question edit, the example input text given was `AAAAAAA BBBBBBBBBB` on a single line. – Weather Vane Jun 04 '15 at 19:57
0

The code compiled normally with a define of MAX_LINE_SIZE = 14. I tried several different ways of getting your output, and the only way that I could was to replace the space char in your input "AAAAAAA BBBBBBBBBB" with ^M. So you may want to look at your input file and see if you have a ^M in it. ^M is ASCII 13 which is a carriage return.

Other than that, the code compiles on a FreeBSD machine using clang. And as someone mentioned, it is highly discouraged to cast the result of malloc, realloc, calloc, and other memory allocation functions. It is also not needed as void* is compatible with all pointer types.

Additionally. I had to add the following lines to the top of the test program to get a compile with 1 warning:

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

#define MAX_LINE_SIZE 14

So your code does work, I believe the problem is in the input.

Daniel Rudy
  • 1,411
  • 12
  • 23