18
char **query; 
query = (char**) malloc ( sizeof(char*) );

int f=0;
int i=0,j=0,c;


while((c=getchar())!=EOF)
{      
    if(!isalpha(c))
        continue;

    if(f==1)
        query=(char**) realloc(query,(i+1)*sizeof(char*));

    query[i]=(char*) malloc(sizeof(char));
    query[i][j]=c;
    j++;


    while( (c=getchar())!=EOF&&c!=' '&&c!='\t' )
    {      

        query[i]=(char*) realloc(query[i],(j+1)*sizeof(char));

        query[i][j]=c;
        ++j;
    }   

    query[i][j]='\0';
    printf("%s\n",query[i]);
    if(c==EOF){

        break;
    }   

   ++i;
   f=1;
   j=0;
}

I want the above code snippet to read a line of strings separated by spaces and tabs until ONE EOF but it requires 2 EOFs to end the loop. Also, strings can consist of only alphabetic characters.

I am struggling on about 2 days. Please, give some feedback.

EDIT: Most probably the reason is I hit CTRL+D keys after I write last string not the enter key, but now I hit enter and then CTRL+D, it works as expected. But, how can I change it to finish after I hit CTRL+D once following the last string?

mualloc
  • 495
  • 9
  • 24
  • 1
    It doesn't require two EOFs to end the loop. It only requires one. Inside the loop, when it has determined it hasn't seen the EOF yet, there's an inner loop that continues scanning input. That inner loop will also stop on EOF (just one) and the subsequent `if(c==EOF)` will break out of the loop when that one EOF has been encountered. – lurker Jan 21 '14 at 14:24
  • 1
    `sizeof(char)` is always one. And [don't cast the return value of `malloc()`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858#605858). –  Jan 21 '14 at 14:25
  • H2CO3 I think sizeof(char)=1 is buggy and if don't cast return value of malloc it returns void. – mualloc Jan 21 '14 at 14:46
  • 3
    `sizeof(char)==1` is absolutely guaranteed by the language. If you don't cast the result of `malloc()`, the `void*` result will be implicitly converted to the target type of the assignment. – Keith Thompson Jan 21 '14 at 15:06

3 Answers3

43

On Unix-like systems (at least by default), an end-of-file condition is triggered by typing Ctrl-D at the beginning of a line or by typing Ctrl-D twice if you're not at the beginning of a line.

In the latter case, the last line you read will not have a '\n' at the end of it; you may need to allow for that.

This is specified (rather indirectly) by POSIX / The Open Group Base Specifications Issue 7, in section 11, specifically 11.1.9:

EOF
Special character on input, which is recognized if the ICANON flag is set. When received, all the bytes waiting to be read are immediately passed to the process without waiting for a <newline>, and the EOF is discarded. Thus, if there are no bytes waiting (that is, the EOF occurred at the beginning of a line), a byte count of zero shall be returned from the read(), representing an end-of-file indication. If ICANON is set, the EOF character shall be discarded when processed.

The POSIX read() function indicates an end-of-file (or error) condition to its caller by returning a byte count of zero, indicating that there are no more bytes of data to read. (C's <stdio> is, on POSIX systems, built on top of read() and other POSIX-specific functions.)

EOF (not to be confused with the C EOF macro) is mapped by default to Ctrl-D. Typing the EOF character at the beginning of a line (either at the very beginning of the input or immediately after a newline) triggers an immediate end-of-file condition. Typing the EOF character other than at the beginning of a line causes the previous data on that line to be returned immediately by the next read() call that asks for enough bytes; typing the EOF character again does the same thing, but in that case there are no remaining bytes to be read and an end-of-file condition is triggered. A single EOF character in the middle of a line is discarded (if ICANON is set, which it normally is).

jfs
  • 399,953
  • 195
  • 994
  • 1,670
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Can you provide reference to your answer,please? – mualloc Jan 21 '14 at 15:06
  • 1
    I haven't been able to track down a reference for this (I'll look again later). But you can try it yourself. At a shell prompt, type `wc`, then type `abc` followed by typing control-D twice. The output should be `abc 0 1 3`, which indicates that `wc` saw 3 characters, of which 0 were newlines. – Keith Thompson Jan 21 '14 at 15:16
  • @nos: I'm sure it's documented somewhere. – Keith Thompson Jan 21 '14 at 15:17
  • @KeithThompson You're right, it's stated here: http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap11.html e.g. in 11.1.9. (And one have to realize that giving input to bash through e.g. an X11 terminal emulator is still munged through an emulator for teletype machines). – nos Jan 21 '14 at 15:24
  • @nos Most current version of same document: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html – This isn't my real name Jan 23 '14 at 18:36
  • @nos: I've looked at 11.1.9, and I don't see how it specifies that Ctrl-D has to be entered *twice* if you're not at the beginning of a line. – Keith Thompson Jan 23 '14 at 18:42
  • @KeithThompson Well, you're right that it doesn't specify that CTRL+D should map to EOF, but it does specify that if there's characters in the buffer those existing characters are processed if EOF occurs and the EOF is discarded. If EOF occurs at the beginning of a line, the EOF is indicated to the reader. Which means if CTRL+D maps to EOF, you have to do it twice when there's data in the buffer, first to process the waiting characters, and a second time to actually indicate EOF – nos Jan 23 '14 at 20:13
  • @nos: (I wasn't referring to whether the character is Ctrl-D.) Ah, I see what you mean. That's a very indirect way of stating it. – Keith Thompson Jan 23 '14 at 20:23
  • 1
    @mualloc: I've updated my answer to (try to) explain how POSIX implies you need to Ctrl-Ds. As for the downvote, I can't explain (I didn't downvote your question myself, and downvotes are anonymous by design), but your question as it's currently written is a bit unclear. I'll update the title in a moment; please check that it still reflects what you're asking. – Keith Thompson Jan 29 '14 at 16:27
  • haha.. Downvotes are disappeared and I got 5 more reputations. Thanks, anyway! – mualloc Jan 29 '14 at 16:49
  • 1
    @mualloc: The downvote on your question is still there. I upvoted it. (You lose 1 rep point for each downvote, gain 5 for each question upvote, and gain 10 for each answer upvote; your question currently has a net score of 0 for which you've gotten a net 4 rep points.) – Keith Thompson Jan 29 '14 at 16:56
1

In the off chance that someone sees this that needs the help I've been needing... I had been searching, trying to figure out why I was getting this strange behavior with my while(scanf). Well, it turns out that I had while (scanf("%s\n", string) > 0). The editor I am using (Atom) automatically put a "\n" in my scan, with out me noticing. This took me hours, and luckily someone pointed it out to me.

tlochner95
  • 127
  • 3
  • 15
0

The Return key doesn't produce EOF that's why the condition getchar() != EOF doesn't recognize it. You can do it by Pressing CTRL+Z in Windows or CTRL+D in Unix.

rullof
  • 7,124
  • 6
  • 27
  • 36