The a modifier to scanf won't work if you are compiling with the -std=c99 flag; make sure you aren't using that.

If you have at least version 2.7 of glibc, you can and should use the m modifier in place of a.

Also, it is your responsibility to free the buffer.

Answer from Nietzche-jou on Stack Overflow
🌐
GNU
gnu.org › software › libc › manual › html_node › Dynamic-String-Input.html
Dynamic String Input (The GNU C Library)
{ char *variable, *value; if (2 > scanf ("%a[a-zA-Z0-9] = %a[^\n]\n", &variable, &value)) { invalid_input_error (); return 0; } ...
🌐
Cprogramming
cboard.cprogramming.com › c-programming › 128708-dynamic-string-input.html
Dynamic string input
July 22, 2010 - int main() { char *dynamic_string; char **string_ptr; int i=0; dynamic_string = (char *)malloc(sizeof(char)); if(dynamic_string == NULL) { printf("Error"); return 1; } string_ptr = &dynamic_string; user_input(string_ptr); printf("%s\n", dynamic_string); return 0; } ... void user_input(char **input_array) { int i; int j; int flag = 0; int string_size = 0; int num_allocated = 1; char * temp; for(i=0; flag!=1; i++) { scanf("%c", *(&input_array[i])); string_size++; if(*input_array[i] == '\n') { *input_array[i] = '\0'; flag = 1; } else { if(string_size == num_allocated) { temp = (char *)malloc(num_
🌐
GNU
gnu.org › software › libc › manual › html_node › String-Input-Conversions.html
String Input Conversions (The GNU C Library)
Ask scanf to allocate a big enough buffer, by specifying the ‘a’ flag character. This is a GNU extension. You should provide an argument of type char ** for the buffer address to be stored in. See Dynamically Allocating String Conversions.
Top answer
1 of 3
8

Given a user input of unknown length (consisting of words with maximum length 100) is there a way to read it dynamically string by string?

Building your own function, instead of scanf would help to achieve this

  • Here, I've created a function scan which would dynamically take in the string by increasing it's size over each iteration

  • I've use the additional header files string.h and stdlib.h for the following reasons :

    1. functions in stdlib.h (click to know more) library file are useful for dynamic allocation of memory.

    2. functions in string.h (click to know more) library file are useful to handle strings.

Note: the input from the user stops when he enters the string end.

#include <stdio.h>  //the standard library file
#include <stdlib.h> //library file useful for dynamic allocation of memory
#include <string.h> //library file with functions useful to handle strings

//the function    
char* scan(char *string)
{
    int c; //as getchar() returns `int`
    string = malloc(sizeof(char)); //allocating memory

    string[0]='\0';

    for(int i=0; i<100 && (c=getchar())!='\n' && c != EOF ; i++)
    {
        string = realloc(string, (i+2)*sizeof(char)); //reallocating memory
        string[i] = (char) c; //type casting `int` to `char`
        string[i+1] = '\0'; //inserting null character at the end
    }

    return string;
}

int main(void)
{
    char *buf; //pointer to hold base address of string

    while( strcmp((buf=scan(buf)),"end") ) //this loop will continue till you enter `end`
    {
        //do something with the string

        free(buf); //don't forget to free the buf at the end of each iteration
    }

    free(buf); //freeing `buf` for last input i.e, `end` 

}

let's just //do something with the string to see whether the above code works or not :)

I change the following while loop in main function :

    while( strcmp((buf=scan(buf)),"end") )
    {
        //do something with the string
    }

to

while( strcmp((buf=scan(buf)),"end") )
{
    printf("you entered : %s\n",buf);
    printf("size        : %u\n",strlen(buf));
    printf("reversing   : %s\n",strrev(buf));

    printf("\n-------------------\n");

    free(buf);
}

and now,

input :

hall
of
fame
stay in it
end

output :

you entered : hall
size        : 4
reversing   : llah

-------------------
you entered : of
size        : 2
reversing   : fo

-------------------
you entered : fame
size        : 4
reversing   : emaf

-------------------
you entered : stay in it
size        : 10
reversing   : ti ni yats

-------------------

2 of 3
2

I found a solution!

while (scanf("%s%c", buf, &c))
    {
        //do something with the string
        if (c == '\n') break;
    }
🌐
CopyProgramming
copyprogramming.com › howto › scanf-variable-length-specifier
Specifying Maximum String Length to scanf Dynamically in C: The Complete 2026 Guide - Maximum string length to scanf dynamically in c the complete
November 13, 2025 - This architectural limitation has ... and simplicity. The most portable and widely-adopted solution is to generate the format string dynamically using snprintf(), then pass the resulting string to scanf()....
🌐
Wikipedia
en.wikipedia.org › wiki › Scanf_format_string
scanf format string
December 3, 2025 - In most cases the input string size from a user is arbitrary and cannot be determined before the scanf function is executed. This means that %s placeholders without length specifiers are inherently insecure and exploitable for buffer overflows. Another potential problem is to allow dynamic formatting strings, for example formatting strings stored in configuration files or other user-controlled files.
Find elsewhere
Top answer
1 of 3
19

Basic answer

There isn't an analog to the printf() format specifier * in scanf().

In The Practice of Programming, Kernighan and Pike recommend using snprintf() to create the format string:

size_t sz = 64;
char format[32];
snprintf(format, sizeof(format), "%%%zus", sz);
if (scanf(format, buffer) != 1) { …oops… }

Extra information

Upgrading the example to a complete function:

int read_name(FILE *fp, char *buffer, size_t bufsiz)
{
    char format[16];
    snprintf(format, sizeof(format), "%%%zus", bufsiz - 1);
    return fscanf(fp, format, buffer);
}

This emphasizes that the size in the format specification is one less than the size of the buffer (it is the number of non-null characters that can be stored without counting the terminating null). Note that this is in contrast to fgets() where the size (an int, incidentally; not a size_t) is the size of the buffer, not one less. There are multiple ways of improving the function, but it shows the point. (You can replace the s in the format with [^\n] if that's what you want.)

Also, as Tim Čas noted in the comments, if you want (the rest of) a line of input, you're usually better off using fgets() to read the line, but remember that it includes the newline in its output (whereas %63[^\n] leaves the newline to be read by the next I/O operation). For more general scanning (for example, 2 or 3 strings), this technique may be better — especially if used with fgets() or getline() and then sscanf() to parse the input.

Also, the TR 24731-1 'safe' functions, implemented by Microsoft (more or less) and standardized in Annex K of ISO/IEC 9899-2011 (the C11 standard), require a length explicitly:

if (scanf_s("%[^\n]", buffer, sizeof(buffer)) != 1)
    ...oops...

This avoids buffer overflows, but probably generates an error if the input is too long. The size could/should be specified in the format string as before:

if (scanf_s("%63[^\n]", buffer, sizeof(buffer)) != 1)
    ...oops...

if (scanf_s(format, buffer, sizeof(buffer)) != 1)
    ...oops...

Note that the warning (from some compilers under some sets of flags) about 'non-constant format string' has to be ignored or suppressed for code using the generated format string.

2 of 3
9

There is indeed no variable width specifier in the scanf family of functions. Alternatives include creating the format string dynamically (though this seems a bit silly if the width is a compile-time constant) or simply accepting the magic number. One possibility is to use preprocessor macros for specifying both the buffer and format string width:

#define STR_VALUE(x) STR(x)
#define STR(x) #x

#define MAX_LEN 63

char buffer[MAX_LEN + 1];
fscanf(file, "%" STR_VALUE(MAX_LEN) "[^\n]", buffer);
🌐
Quora
quora.com › What-is-the-problem-with-this-C-code-dynamic-string-input
What is the problem with this C code (dynamic string input)? - Quora
Answer (1 of 3): The problem with this is that you have declared the pointer as char *str this will simply initialize a pointer of character type and it will not allocate memory for the string and if you are thinking that the gets will allocate the memory than let me clear that gets does not all...
🌐
Cplusplus
cplusplus.com › forum › beginner › 46399
dynamic string sscanf reading problem - C++ Forum
Then the first char of kimber[0] would be kimber[0][0]. What I said earliar applies only to c style strings. Sorry ... waw... thanks alot. so i will be using (*ptr).function when i need to access memory and send it to function.sometimes im so lost in these things; you wont learn such specific things anywere. if you can recommend a book or tutor on this exact subject youll help me alot. key moment here is that dynamic string and static one behave differently when we call it's first element string first = "hi its first string"; string * dynstring; dynstring= new string[2]; //dynamic with 2 indip
🌐
Quora
quora.com › How-do-you-use-fscanf-for-two-strings-of-any-length-and-de-allocate-the-memory-properly-C-scanf-development
How to use fscanf() for two strings (of any length) and de-allocate the memory properly (C, scanf, development) - Quora
Yes, you can use scanf() function in C. You need to include stdio.h file in the begining of the program to use it. Like this: ... How do you properly dynamically allocate a string (C, string, pointers, memory management, malloc, development)?
🌐
GitHub
gist.github.com › qlife › 879f7a9437e59fe37ad6
scanf() with 'm' modifier to allocate memory for C string · GitHub
scanf() with 'm' modifier to allocate memory for C string · Raw · gistfile1.c · This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Top answer
1 of 2
2

It would be wise to check if the reallocation of the memory worked.

Also, this:

copy=malloc(strlen(output)+1); /* allocate memory for copy of output +1 for \0 char */
if(copy==NULL)
  return NULL;
strcpy(copy, output); /* strcpy output to copy */
free(output);  /* free memory taken by output */
return copy;

Why making a copy of output, freeing output, and then returning copy? Why not just returning output?

Here is a chunk of code I wrote a few years ago, which I find a bit simpler than your code:

char * read_string(void) {
  char *big = NULL, *old_big;
  char s[11] = {0};
  int len = 0, old_len;

  do {
    old_len = len;
    old_big = big;
    scanf("%10[^\n]", s);
    if (!(big = realloc(big, (len += strlen(s)) + 1))) {
      free(old_big);
      fprintf(stderr, "Out of memory!\n");
      return NULL;
    }
    strcpy(big + old_len, s);
  } while (len - old_len == 10);
  return big;
}

This was just a learning example, which I have never really used. In practice, I'd suggest working with a larger s (char s[1025], %1024[^\n] in scanf, and len - old_len == 1024 in the condition of the do...while loop) to reduce the number of realloc calls which can be very slow if the user gets unlucky. This also answers your last question: char-by-char might get very slow and is in no way better than chunks.

2 of 2
3

Here are a few comments on your function:

  • Firstly, read_line seems a more accurate name, as you read up until the next \n.

  • Reading 10 chars at a time is an odd. Unless that is part of the requirement I think you should allocate a bigger buffer and read as many chars as fit, extending the buffer each time round the loop by doubling its size (instead of adding 11).

  • As you have it, your fgets call overwrites the char after the end of the buffer with \0. You should pass the actual size of the buffer to fgets.

  • Your fgets/strcat/strlen sequence is inefficient. You should be reading directly into the target buffer rather than reading and then copying. And the strcat call has to traverse the whole length of the accumulated string to concatenate the new part.

    char *p = buf;
    size_t len = 0;
    
    while (fgets(p, size - len, stdin) != NULL) {
        len += strlen(p);
        if (buf[len-1] == '\n') {
            buf[len-1] = '\0';
            break;
        }
        ...
    }
    
  • Your reallocation call leaks memory if it fails to allocate - you need a temporary variable to hold the return value from realloc:

    size *= 2;
    if ((p = realloc(buf, size)) == NULL) {
        break; // and then return an error if `p == NULL` or `ferror`
    }
    buf = p;
    p += len;
    
  • Your loop exits when fgets returns NULL, but you do not check for an error.
    You must call ferror to be sure that an error did not occur.

  • And your looping at the end to find the \n seems wasteful when you have already located the end of line/string in the main loop.

  • From the task statement you posted, copying the dynamic string is not required.

Note that reading character at a time is not necessarily a slower solution. As you are doing it (with all that the copying and string traversal), I would expect a well written character-at-a-time function to be faster. I encourage you to try both and compare the execution speed (using a very big test file as input).

🌐
LinuxQuestions.org
linuxquestions.org › questions › programming-9 › dynamic-memory-allocation-malloc-scanf-513402
dynamic memory allocation - malloc, scanf!
December 24, 2006 - Hello, I'm learning C at the moment and am confused about how to dynamically allocate memory at runtime. If I wanted to read a variable sized string
🌐
GeeksforGeeks
geeksforgeeks.org › c language › scanf-in-c
scanf in C - GeeksforGeeks
%ld to accept input of long integers %lld to accept input of long long integers %f to accept input of real number. %c to accept input of character types. %s to accept input of a string.
Published   October 13, 2025
🌐
Itecnote
itecnote.com › tecnote › dynamic-string-input-using-scanfas
Dynamic String Input – using scanf(“%as”) – iTecNote
I am trying to read input using scanf and storing into char * dynamically as specified by GCC manual, But it is giving a compile time error. char *string; if (scanf ("%as",&string) != 1){ //some code } else{ printf("%s\n", *string); free(string); //some code }