views:

644

answers:

4

I am trying to read strings from a file that has each string on a new line but I think it reads a newline character once instead of a string and I don't know why. If I'm going about reading strings the wrong way please correct me.

    i=0;
F1 = fopen("alg.txt", "r"); 
F2 = fopen("tul.txt", "w"); 
     if(!feof(F1)) {
     do{ //start scanning file
     fgets(inimene[i].Enimi, 20, F1);
     fgets(inimene[i].Pnimi, 20, F1);
     fgets(inimene[i].Kood, 12, F1);
     printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s",i,inimene[i].Enimi,inimene[i].Pnimi,inimene[i].Kood);
     i++;}
     while(!feof(F1));};
/*finish getting structs*/

The printf is there to let me see what was read into what and here is the result

i=0
Enimi=peter

Pnimi=pupkin

Kood=223456iatb i=1
Enimi=

Pnimi=masha

Kaad=gubkina
i=2
Enimi=234567iasb

Pnimi=sasha

Kood=dudkina

As you can see after the first struct is read there is a blank(a newline?) onct and then everything is shifted. I suppose I could read a dummy string to absorb that extra blank and then nothing would be shifted, but that doesn't help me understand the problem and avoid in the future.

Edit 1: I know that it stops at a newline character but still reads it. I'm wondering why it doesn't read it during the third string and transfers to the fourth string instead of giving the fourth string the fourth line of the source but it happens just once. The file is formatted like this by the way

peter 
pupkin 
223456iatb 
masha 
gubkina 
234567iasb 
sasha 
dudkina 
123456iasb 
A: 

the fgets function reads newline char as a part of the string read.

From the description of fgets:

The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a newline is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.

codaddict
+2  A: 

fgets stops reading when it reads a newline, but the newline is considered a valid character and is included in the returned string.

If you want to remove it, you'll need to trim it yourself:

length = strlen(str);
if (str[length - 1] == '\n') 
    str[length - 1] = '\0';

Where str is the string into which you read the data from the file, and length is of type size_t.

To answer the edit to the question: the reason the newline is not read during the third read is because you are not reading enough characters. You give fgets a limit of 12 characters, which means it can actually read a maximum of 11 characters since it has to add the null terminator to the end.

The line you read is 11 characters in length before the newline. Note that there is a space at the end of that line when you output it:

Kood=223456iatb i=1
               ^
James McNellis
+3  A: 

As already stated, if there's enough room in the buffer, then fgets() reads the data including the newline into the buffer and null terminates the line. If there isn't enough room in the buffer before coming across the newline, fgets() copies what it can (the length of the buffer minus one byte) and null terminates the string. The library resumes reading from where fgets() left off on the next iteration.

Don't mess with buffers smaller than 2 bytes long.

Note that gets() removes the newline (but does not protect you from buffer overflows, so do not use it). If things go as currently planned, gets() will be removed from the next version of the C standard; it will be a long time before it is removed from C libraries (it will just become a non-standard - or ex-standard - additional function available for abuse).

Your code should check each of the fgets() function calls:

while (fgets(inimene[i].Enimi, 20, F1) != 0 &&
       fgets(inimene[i].Pnimi, 20, F1) != 0 &&
       fgets(inimene[i].Kood,  12, F1) != 0)
{
    printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s", i, inimene[i].Enimi, inimene[i].Pnimi, inimene[i].Kood);
    i++;
}

There are places for do/while loops; they are not used very often, though.

Jonathan Leffler
Wow, thanks for the second part, it got rid of my second problem: an empty extra struct. It was hard finding an example for a loop to get strings from file(or maybe I didn't look properly, although I kept trying for a long time).
Ivan
A: 

if Enimi/Pnimi/Kood are arrays not pointers:

while( fgets(inimene[i].Enimi,sizeof inimene[i].Enimi,F1) &&
       fgets(inimene[i].Pnimi,sizeof inimene[i].Pnimi,F1) &&
       fgets(inimene[i].Kood,sizeof inimene[i].Kood,F1) )
{
if( strchr(inimene[i].Enimi,'\n') ) *strchr(inimene[i].Enimi,'\n')=0;
if( strchr(inimene[i].Pnimi,'\n') ) *strchr(inimene[i].Pnimi,'\n')=0;
if( strchr(inimene[i].Kood,'\n') ) *strchr(inimene[i].Kood,'\n')=0;
printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s", i, inimene[i].Enimi, inimene[i].Pnimi,inimene[i].Kood);
    i++;
}