Reading from Stdin in C++

Reading in exactly N bytes from standard input in C

To read exactly 4 bytes from stdin, you can use fread(), getc() or scanf():

  • fread(&f, sizeof f, 1, stdin);
  • char *p = (char *)&f; for (size_t i = 0; i < sizeof(f); i++) p[i] = getchar();
  • char *p = (char *)&f; for (size_t i = 0; i < sizeof(f); i++) p[i] = getc(stdin);
  • char *p = (char *)&f; scanf("%c%c%c%c", p, p+1, p+2, p+3);

Note however that stdin is open in text mode by default on legacy systems that perform line ending translation, and there is no portable way to change this mode on an open stream.

how to read a line from stdin again after reading something from stdin in C?

Seems like fflush(stdin) (it is undefined as already mentioned) does not work properly. The problem is the '\n' which is still in the buffer and has to be removed. Otherwise fgets is called, finds the '\n' in the buffer (which marks the end of the input) and continues with the program.

Try this instead:

    // fflush(stdin);
while (getchar() != '\n');
printf("Type something:\n");
char* message = (char*) malloc(64 * sizeof(char));
fgets(message, 64, stdin);
printf("message is : %s\n", message);
free(message);

What also works fine (but probably unintended) is an input like "p MyMessage". This prints the message indeed.

C reading lines from stdin

I've reproduced the linking error on DevC++, in which getline() seems to be missing even after forcing recent C revisions with gcc compiler options such as -std=c11.

So I've rewritten your code using fgets():

char *fgets(char *s, int size, FILE *stream);

It is for sure more portable than getline but has a few differences:

  • It reads up to size-1 characters if the newline is not encountered before this limit (it automatically appends the string terminator). So it doesn't manage buffer reallocation
  • The resulting string contains the '\n' character, if found
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_STR_SIZE 32

int main( void )
{
int len = 0;
char *str;

printf("Please enter a string: ");
str = malloc(MAX_STR_SIZE); /* (1) */

while( 1 )
{
size_t newline_pos;

fgets( str, MAX_STR_SIZE, stdin );
/* (2) */

if( len == 0) /* (3) */
{
puts("You entered the following string: ");
}

newline_pos = strcspn(str, "\n" );

str[newline_pos] = '\0';
len += strlen(str); /* (4) */
fputs(str, stdout);

if(newline_pos < MAX_STR_SIZE-1) /* (5) */
break;
}

printf("\n\nCurrent size for string block: %d", len);

free( str ); /* (6) */
return 0;
}

So, basically, I just use fgets to read from stdin, iterating until the '\n' character is found. In order to understand is this condition is met, I use strcspn() function, and I use the same function to remove the newline from the resulting string.

A few notes/assumptions (check the corresponding number in code section):

  1. Casting the result of malloc is required only if you are compiling with a C++ compiler. It can be omitted in C
  2. Removed fgets error check: it returns NULL in case of error (no chars read before EOF is found. It won't happen reading from stdin)
  3. Checking for len==0 we make sure that the "You entered the following string: " is printed only once
  4. The length of the string is calculated by summing the length of the strings read in every iteration
  5. The break condition is met when the string contains '\n'. Otherwise strcspn's return value will be MAX_STR_SIZE
  6. Even if the OS will release all the dynamic memory used by the program, on return, it is a good habit always freeing it anyway


Related Topics



Leave a reply



Submit