Is there any function to get an unlimited input string from standard input
Asked Answered
T

5

10

The condition is:

I want to input a line from standard input, and I don't know the size of it, maybe very long.

method like scanf, getsneed to know the max length you may input, so that your input size is less than your buffer size.

So Is there any good ways to handle it?

Answer must be only in C, not C++, so c++ string is not what I want. I want is C standard string, something like char* and end with '\0'.

Tamartamara answered 14/12, 2014 at 4:39 Comment(4)
MAYBE Is there anything that can automatic allocate memory according to your input size in C?Tamartamara
Rarely is this functionality useful. Far more often with code that handles unlimited input, some input occurs, that is processed, then more input. etc. With realistic user input with something like a person's name, phone number or book title, yes certainly there are names/titles 100s of char long and phone numbers with dozens of digits. But allowing unlimited input invites hackers to overwhelm systems with billion long names/titles etc. Far better to allow for exceptional, even pathological long input, but not unlimited. fgets(user_name, 1000, stdin) is sufficient.Agnostic
gets does not let you specify the size of the target array. That's what makes it inherently unsafe, which is why it's been removed from the language as of the 2011 ISO C standard. Were you thinking of fgets?Propylene
The way to read an unknown amount of data strongly depends on how the data shall be processed by the reader. You might like to provide any details on this?Bustee
P
9

The C standard doesn't define such a function, but POSIX does.

The getline function, documented here (or by typing man getline if you're on a UNIX-like system) does what you're asking for.

It may not be available on non-POSIX systems (such as MS Windows).

A small program that demonstrates its usage:

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    char *line = NULL;
    size_t n = 0;
    ssize_t result = getline(&line, &n, stdin);
    printf("result = %zd, n = %zu, line = \"%s\"\n", result, n, line);
    free(line);
}

As with fgets, the '\n' newline character is left in the array.

Propylene answered 14/12, 2014 at 5:42 Comment(0)
P
5

One way is to run a loop with getchar and keep placing the characters into an array. Once the array is full, reallocate it to a larger size.

Piano answered 14/12, 2014 at 4:41 Comment(4)
Cool!! Does any C library function implement it?Tamartamara
@youKnowDai Bro it is C, you have to do it all yourself and create libraries.Progeny
There is not function getch() in Standard C. You probably meant getc() or getchar()?Bustee
Yes I meant getchar, just fixed it. Thank you for pointing that out!Piano
C
1

One of the method is using getchar() function we can get input in a character and transfer it to dynamicall created array. You can see that when it exceeds the default length set by us, we reallocated space for storing character

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

void main(){
    int size = 10;
    char* str;
    str = (char*) calloc(size,sizeof(char));
    char c;
    c = getchar();
    int t = 0;
    int cnt = 0;
    int len;

    while(c!='\n') {
        if(cnt > size) {
            str = (char*) realloc(str,2*cnt);
        }

        str[t] = c;
        c = getchar();
        t++;
        cnt++;
    }
        str[t]='\0';
    printf("The string is %s\n",str);
    len = strlen(str);
    printf("The size is %d",len);
}
Constantine answered 9/12, 2017 at 18:10 Comment(0)
C
0

There is an often overlooked conversion specification within scanf that will allocate memory sufficient to hold the string input regardless of length. Newer versions of scanf use m for this purpose. Older versions used a. For example:

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

int main (void) {
    char *str = NULL;
    printf (" enter a string of any length, whitespace is OK: ");
    scanf ("%m[^\n]%*c", &str);
    printf ("\n str: %s\n\n", str);
    if (str) free (str);
    return 0;
}

Note: scanf requires a char ** pointer argument to receive the allocated string. Also note scanf does not include the '\n' in the stored string. Further note the %*c which receives and discards the '\n' character to prevent the newline from remaining in the input buffer. You may also precede the conversion specifier with whitespace to skip any/all whitepace that may exist in the input buffer.

Lastly Note: there are reports that not all implementations of scanf offer this feature. (which may also be confusion of the m/a change) Check your implementation.

Childbirth answered 14/12, 2014 at 8:40 Comment(7)
This use of 'm' is defined by POSIX, but not by ISO C.Propylene
Correct, and it was 'a' before 'm', so you must check the man page for your version of scanf -- good point.Childbirth
@NehalSamee What compiler are you using?Childbirth
Well... yes... but on Windows with MinGW or Cgywin as the compiler. Or on Linux with gcc or clang. I don't believe the MinGW versions support it. If you installed C::B with the compiler already with it, then it is likely TDM-MinGW, good compiler, but doubtful support of the m modifier.Childbirth
In fact, I just checked and TDM-MinGW does not support the 'm' modier.Childbirth
Then what should i do?Fricandeau
Either declare a buffer of sufficient size to hold your input and add a char at a time, or allocate storage for the buffer with malloc and keep track of the number of characters you add, and when you reach your allocated limit, realloc to double the size of the buffer and keep going.Childbirth
G
0

use getchar, malloc and realloc for reading the unlimited input string

Declare String type, you can also use char *

// String type
typedef char *String;

I write this function for joining the char in the end of string

/**
 * Join the Char into end of String
 *
 * @param string - String
 * @param c - joined char
 */
void String_joinChar(String *string, const char c)
{
  const size_t length = strlen(*string);
  (*string) = (String)realloc((*string), sizeof(char) * (length + 2));
  (*string)[length] = c;
  (*string)[length + 1] = '\0';
}

This function for inputting string, which read the char from keyboard by using getchar and join it in the end of current string.

/**
 * Input String
 *
 * @return Inputed String
 */
String String_input()
{
  String string = (String)malloc(sizeof(char));
  strcpy(string, "");

  char cursor;
  fflush(stdin);
  while ((cursor = getchar()) != '\n' && cursor != EOF)
  {
    String_joinChar(&string, cursor);
  }

  return string;
}

Cause of using char *, malloc and realloc, we must free it

/**
 * Destroy String
 *
 * @param string - Destroyed String
 */
void String_destroy(String string)
{
  free(string);
}

And now we just use it !!

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

int main()
{
  String string = String_input();
  printf("\n%s\n", string);
  String_destroy(string);
  return 0;
}

Hope useful to you!

Geibel answered 4/3, 2020 at 22:50 Comment(2)
From practical point of view reallocating array of size X to size X + 2 is ineffective - you would reallocate on every second input char the whole array. It is better to reallocate to size X * 2. This way you would reach constant amortized asymptotic time complexity instead of linear complexity of the insert operation into dynamic array.Superfine
@Superfine You are right, if it does then it will reach constant amortized asymptotic time complexity, but it will come to the so-called memory consumption over time if the input sequence consists of infinity characters. infinity * 2 = super infinity :)) hahahaGeibel

© 2022 - 2024 — McMap. All rights reserved.