1

I would like to know if there is any way to dynamically allocate some memory when/before using a scanf. This would mean that there is no need to give a char * a size when initializing it. Instead of this, the quantity of memory needed would be allocated depending on the size of the input string (which means: after having the input).

Currently I find no other solution than to allocate a specific quantity of memory before having the input, so before knowing the size of the input:

char str[10];
scanf("%s", str);

And I know this is not safe: if the input is longer than 10 characters, the program will write on unallocated memory, which can cause segfaults or stuff like that.

nounoursnoir
  • 671
  • 2
  • 10
  • 25
  • 1
    What's stopping you from writing a function that does exactly what you want? (Also, your declaration for `str` creates an array of ten pointers, which is probably not what you wanted.) – David Schwartz May 01 '17 at 09:50
  • 1
    Don't use `scanf` for user input in the first place. – melpomene May 01 '17 at 09:50
  • @DavidSchwartz My skills are not high enough for this. I tried to read the libraries but understood pretty much nothing of what was written in it (except comments :) ) – nounoursnoir May 01 '17 at 09:51
  • 6
    http://stackoverflow.com/questions/2329909/dynamic-string-input-using-scanfas – melpomene May 01 '17 at 09:52
  • 1
    @nounoursnoir Then stick to doing it the easy way that everyone else does and when you understand that thoroughly, then maybe think about building something more complicated. Do it your own way after you learn the way everyone else does it. Maybe you'll find you don't need to. – David Schwartz May 01 '17 at 09:54
  • words of wisdom have been spoken – nounoursnoir May 01 '17 at 09:55
  • 2
    [difference-between-ms-and-s-scanf](http://stackoverflow.com/questions/38685724/difference-between-ms-and-s-scanf) –  May 01 '17 at 10:03
  • 3
    I am a bit late on that topic unforunately, but you can use this manual https://linux.die.net/man/3/scanf. The example section let you see how to use the %m appropriately. note comments @melpomene for possible differences on your libc version though... – Aviv May 01 '17 at 10:40
  • `%m` is a [POSIX standard format specifier for `scanf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html): "An optional assignment-allocation character `'m'`". It's not just Linux. – Andrew Henle May 01 '17 at 13:55

3 Answers3

1

As pointed in comments, %m I believe solves your query

Another approach will be to limit the input to number byte you know you have allocated to your variable with eg %10s will input only 10 characters Then reallocating your input variable to make room for more character to be input in next call to scanf, you need to pass str like &str[10] in next call so that it does not overwrite earlier input

Pras
  • 4,047
  • 10
  • 20
1

User input from stdin is tricky.


OP's "if the input is longer than 10 characters, the program will write on unallocated memory" is an off-by 1 problem. If input is longer than 9, the program will attempt to write outside str[].

char str[10];
scanf("%s", str);  // Trouble with input more than 9

getline();, as suggested by this good answer is the typical solution.

I am rejecting the idea of "dynamic allocation during a scanf" as a good design goal. A program that allows for endless input is prone to abuse. It allows the user to overwhelm system resources. Good code validates input first. No more Heartbleed.

Instead I recommend that stdin input is assessed for a reasonable input length, be it 10, 1000, or 1,000,000 and a buffer of 2x or so is provided.

#define MAX_EXPECTED_SIZE 100
char buf[MAX_EXPECTED_SIZE * 2];
if (fgets(buf, sizeof buf, stdin)) {
  size_t len = strlen(buf);
  if (len + 1 == sizeof buf && buf[len] != '\n') {
    // Assume hostile input and act accordingly. Possibly exiting with message.
    // or consume rest of line
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF);

    return ERROR_LONG_LINE
  }

  // Use buf[]
}

Code can allocate the right-sized memory afterward if a copy of buf needs to be retained.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • The fact that an array is dynamicly allocated does not mean that it size is controllable by the user. – Wouterr May 28 '20 at 14:08
  • @Wouterr With `getline()` the user of program can provide a huge long line of input - billions, obliging the code to allocate huge memory resources - thus proving the user a level of control over the program - a form of [DoS](https://en.wikipedia.org/wiki/Denial-of-service_attack#Application-layer_attacks). This abuse of say an "Enter your name" function is not prevented by `getline()` when an upper bound of say 2K is [sufficient](https://en.wikipedia.org/wiki/Hubert_Blaine_Wolfeschlegelsteinhausenbergerdorff_Sr.). The underlying OS _may_ provide some attack detection, but is not required. – chux - Reinstate Monica May 28 '20 at 15:06
  • @Wouterr "thus proving the user" --> "thus providing the user". – chux - Reinstate Monica May 28 '20 at 17:45
0

Use the getline function,

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

Example Try Online

int main(void)
{
    char * line;
    size_t size;

    if(getline(&line, &size, stdin) != (-1))
    {
        printf("You entered: %s",line);
    }

    return 0;
}
Khaled.K
  • 5,828
  • 1
  • 33
  • 51
  • Your `readLineString` is unsafe and uses a static buffer of length 512. This is not dynamic in any way. (It then does a manual version of `strdup` but what is that good for?) – melpomene May 01 '17 at 10:46
  • @melpomene I agree, how would you read input with dynamic length? – Khaled.K May 01 '17 at 11:08
  • 1
    [`getline`](http://man7.org/linux/man-pages/man3/getdelim.3.html) if I'm feeling lazy and it doesn't have to be portable. – melpomene May 01 '17 at 11:10
  • @melpomene solution changed to use `getline` now – Khaled.K May 01 '17 at 11:24
  • Is it better to use the `getline()` function, or the "m" modifier in a `scanf()`? How is it different? – nounoursnoir May 01 '17 at 11:27
  • @nounoursnoir `scanf` only works with constant-size buffer, while `getline` will read the input dynamically – Khaled.K May 01 '17 at 11:31
  • it seemed to me that a constant-size buffer only means that it cannot be modified. Isn't it? I don't see any modification in `getline` or `scanf`... I may not fully understand what means a dynamic reading... – nounoursnoir May 01 '17 at 12:10
  • 1
    @nounoursnoir dynamic reading means you read a line of any length, in case `scanf` you need something like `char buffer[512]` which means you can only read up to 512 characters from input, also constant-size buffer means its size is constant not its content. – Khaled.K May 01 '17 at 13:17
  • @melpomene [`getline()` is POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html). – Andrew Henle May 01 '17 at 13:59