3

I want to read a string from the console.

Using scanf or fgets however, it seems to me that it's only possible to read a string of a fixed maximum size. Even worse, there seems to be no way of checking how many characters were entered in case the user enters too much (in that case I could simply realloc the array in order for the string to fit into the array).

I read that I'm supposed to read one character at a time in the answer to this question, however I don't know how to read one character at a time without having the user press enter after each character.

How can I do it?

Community
  • 1
  • 1
TravisG
  • 2,373
  • 2
  • 30
  • 47
  • 1
    The characters that the user enters are buffered until the user presses enter, but you can still read them one at a time. The reading just won't start until the user has pressed enter. – Vaughn Cato Mar 17 '12 at 14:59
  • [How can I read an input string of unknown length?](https://stackoverflow.com/q/16870485/608639) – jww Dec 08 '18 at 07:01

5 Answers5

4

The GCC documentation says that:

Standard C has functions to do this, but they aren't very safe: null characters and even (for gets) long lines can confuse them. So the GNU library provides the nonstandard getline function that makes it easy to read lines reliably.

and that

[getline] is a GNU extension, but it is the recommended way to read lines from a stream. The alternative standard functions are unreliable.

So if you're using GCC, I'd say you should use getline. If you're not using GCC, you should see if your compiler offers a similar feature. If it doesn't — or if you really prefer to use something standard — then you need to read one character at a time.

I don't know how to read one character at a time without having the user press enter after each character.

Yes, you do. The user enters a sequence of characters, and then presses Enter. Your first fgetc call will block until the user presses Enter, but after that, subsequent fgetc calls will return immediately, up until you read the newline. (Then it will block again, until the user presses Enter again.) Reading "one character at a time" doesn't mean that you have to read each character before the user types the next one; it just means that, once the user is done typing a line, you read that line one character at a time.

ruakh
  • 175,680
  • 26
  • 273
  • 307
1
char c = NULL;
while (c != 0x0D)
{
    scanf("%c", &c);
    // do stuffs with c
}
QuantumBlack
  • 1,549
  • 11
  • 27
1

Try running this..

#include <stdio.h>

int main(){
    char next;
    while((next=getchar())!=EOF)
        printf("%c\n",next);

}

then check out the man page for getchar() to see what's really at hand.

FrankieTheKneeMan
  • 6,645
  • 2
  • 26
  • 37
  • Thanks. This is the simplest answer that demonstrated what I need to solve the problem. – TravisG Mar 17 '12 at 16:00
  • 1
    Should be `int next`, otherwise you can't tell the difference between EOF and '\xff' (or you'll loop forever if char is unsigned). – zaphod Feb 25 '16 at 01:06
1

You can use fgets() in a loop and realloc if the last character is not a \n

/* UNTESTED: MAY HAVE OFF-BY-ONE ERRORS */
char *buffer;
size_t bufsiz = 100;
size_t buflen = 100;
size_t bufcur = 0;
buffer = malloc(bufsiz);
for (;;) {
    fgets(buffer + bufcur, bufsiz, stdin);
    buflen = bufcur + strlen(buffer + bufcur);
    if (buffer[buflen - 1] == '\n') break;
    tmp = realloc(buffer, bufsiz * 2);
    if (tmp == NULL) /* deal with error */;
    buffer = tmp;
    bufcur = buflen - 1;
    bufsiz *= 2;
}
/* use buffer (and bufsiz and buflen) */
free(buffer);
pmg
  • 106,608
  • 13
  • 126
  • 198
1

The accepted answer should note that getchar() returns an int. The char data type is not big enough to hold EOF.

We could read a predetermined amount of text and then discard the rest of the input. That approach has more than its share of critics (how dare we presume to know what to discard). The other option is to use getline or write a custom function. I thought I'd try the latter.

This does not prevent users from filling up memory with cat large_file.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define MAX 50
#define JUSTDO(a) if (!(a)) {perror(#a);exit(1);}
/** char *get_line  FILE *f
 * reads an arbitrarily long line of text or until EOF
 * caller must free the pointer returned after use
 */
char *get_line (FILE *f) {
    int len=MAX;
    char buf[MAX],*e=NULL,*ret;JUSTDO (ret=calloc(MAX,1));
    while (fgets (buf,MAX,f)) {
        if (len-strlen(ret)<MAX) JUSTDO (ret=realloc(ret,len*=2));
        strcat (ret,buf) ;if ((e=strrchr (ret,'\n'))) break;
    } if (e) *e='\0';
    return ret;
}
/* main */
int main (void) {
    char *s;
    printf ("enter a line of text:\n");
    printf ("line was '%s'\n",s=get_line(stdin)) ;free (s);
    return 0;
} 
hellork
  • 420
  • 2
  • 5
  • Just... just wrong. http://linux.die.net/man/3/getchar. The man page CLEARLY states fgetc(), getc() and getchar() return the character read as an unsigned char cast to an int or EOF on end of file or error. EOF, while system dependent, is usually -1 (or a word of all 1 bits). – FrankieTheKneeMan Aug 10 '12 at 16:43