10

For whatever reason the following code prints (null):

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

int main(void)
{
    char *foo; 
    scanf("%ms", &foo);
    printf("%s", foo);
    free(foo);
}

I'm trying to allocate memory for a string dynamically but as I said earlier my program simply outputs (null). I worked around this by making a function using getche and realloc but it seems almost pointless due to the fact that I also had to program what would happen if the user entered backspace, tab, etc.. But as I said that is just a work around and I would rather know why the above code is not working...

Additional Information:

I am using the Pelles C IDE v7.00 and compiling with the C11 standard

Keith Miller
  • 1,317
  • 1
  • 16
  • 32
  • What is `%ms` intended to do? – Greg Hewgill Aug 13 '12 at 00:18
  • @Greg The m flag should dynamically allocate memory to contain the input. – Keith Miller Aug 13 '12 at 00:22
  • 3
    Is that nonstandard? I don't see that in my `scanf` documentation. – Greg Hewgill Aug 13 '12 at 00:23
  • 1
    I don't see anything about `m` flag in my copy of C11 (which is, admittedly, a draft). Where did you get it? It looks to me as something chiefly GCC specific, which you are unlikely won't find in any other library implementation. – AnT Aug 13 '12 at 00:28
  • 2
    http://gcc.gnu.org/ml/gcc-patches/2007-09/msg01342.html Maybe my compiler doesn't support it? and in C99 there was the `a` flag I thought the `m` flag was the new version of this according to this document – Keith Miller Aug 13 '12 at 00:28
  • That's a shame, such a great little flag but I can't use it. – Keith Miller Aug 13 '12 at 00:43
  • 4
    The `m` flag is in POSIX now, added in the 2008 edition. The good thing about standards... – Alan Curry Aug 13 '12 at 00:44
  • I'm sorry but I'm not sure what that means for me, what would I have to do to utilize the `m` flag? – Keith Miller Aug 13 '12 at 00:47
  • Your `foo` already is a pointer, so you should not use `&foo` (address of `foo`) when passing it to `scanf`. `scanf("%ms", foo);` is correct. – Palec Nov 05 '14 at 07:01
  • 3
    @Palec `scanf("%ms", &foo);` is correct. The `%ms` specifier allocates memory and "returns" a pointer to that memory. The initial value of `foo` is unused. – M.M Jun 01 '15 at 05:58
  • You’re right, @MattMcNabb. Thanks for disabusing me! – Palec Jun 01 '15 at 07:10

6 Answers6

9

I am not seeing %m in section 7.21.6.2 of the Draft C11 standard (the section on fscanf). I suggest that you avoid it and call malloc() as you would in C99.

Norman Ramsey
  • 193,779
  • 59
  • 352
  • 532
  • 3
    Seeing as you can't predict how much space to allocate with `scanf("%s")`, I'd also recommend avoiding `scanf` entirely and using `fgets` and `sscanf`. – jamesdlin Apr 16 '13 at 18:10
  • 7
    The `%ms` notation is a POSIX extension in [`scanf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/scanf.html) compared with the standard C version of `scanf()`. – Jonathan Leffler Nov 11 '13 at 00:02
  • Maybe use this in conjunction with a method that tells you how big the data is, that you receive in advance (on the stack). Just an idea. – Vandrey Mar 14 '20 at 22:40
2

%m is a POSIX extension, which may be why it's not available in Pelles C.

ulatekh
  • 1,131
  • 13
  • 18
1

There is an example in the man page for scanf/sscanf (page 3, from line 270-290) that states the following:

EXAMPLE

To use the dynamic allocation conversion specifier, specify m as a length modifier (thus %ms or %m[range]). The caller must free(3) the returned string, as in the following example:

char *p;
int n;

errno = 0;
n = scanf("%m[a-z]", &p);
if (n == 1) {
   printf("read: %s\n", p);
   free(p);
} else if (errno != 0) {
   perror("scanf");
} else {
   fprintf(stderr, "No matching characters\n");
}

As shown in the above example, it is necessary to call free(3) only if the scanf() call successfully read a string.

Source: SCANF(3) - Linux Programmer's Manual - GNU - 2013-01-30

Palec
  • 11,499
  • 7
  • 57
  • 127
Steve
  • 11
  • 1
0

I am using Linux 3.2.0 amd 64 with gcc 4.7.2. Using the code:

char *s; 
scanf("%ms", &s);
printf("%s", s);
free(s);

works fine but it won't accept whitespaces.

For static allocation, you can instead use:

char s[100];
printf("Enter string (max 99 characters): ");
scanf("%100[^\n]s", &s);
printf("You entered: %s\n", s);

Hope it helps!

Arun
  • 1,874
  • 2
  • 31
  • 59
  • Sorry for that but you are not helping him because if you take a look at your `scanf()` function you will definitely realize that it is wrong ! it should be `scanf("%ms", s)` as s is a pointer in itself ! Please note that there is no `&` before the `s`. Besides keep in mind that it will not work for the next `scanf` in the program if there are any !!! Hope it is clear !!! – Meninx - メネンックス Jan 18 '15 at 14:31
  • 6
    @Meninx: no, with `%ms`, it should be `scanf("%ms", &s)`. The POSIX `m` extension allocates the string for you and assigns it to `s`, which must be of type `char*`. – Rudy Velthuis Jul 31 '16 at 16:02
  • The `scanf("%ms", &s)` is correct, the call modifies the pointer stored in `s`. However, **the `scanf("%100[^\n]s", &s)` is wrong**. It needs to be `scanf("%99[^\n]", s)`. In this case, the pointer to the first byte of the buffer needs to be passed by value, so `s` is correct. And the `s` after the closing bracket `]` is wrong, it's not part of the conversion. But, most importantly, the buffer must be longer than the field width to leave room for the terminating null byte. **Using a field width of 100 for a 100 byte buffer allows users to overrun the buffer**. – cmaster - reinstate monica Mar 14 '20 at 22:50
0

as Arun says, this solution is right and Meninx's opinion is wrong:

char *s;
scanf("%ms", &s);
printf("%s", s);
free(s);

I have read the 'man scanf', it says:

An optional 'm' character. This is used with string conversions(%s, %c, %[),
and relieves the caller of the need to allocate a corresponding buffer to hold the input: instead, scanf() allocates a buffer of sufficient size, and assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char * variable (this variable does not need to be initialized before the call). The caller should subsequently free(3) this buffer when it is no longer required.

Community
  • 1
  • 1
zhangjie
  • 171
  • 10
-1

Char* is a pointer, therefore when its passed as argument, there is no need for &pointer

  • I think in this context and with what the OP is trying to do, your answer is incorrect. scanf can take a `char**` if you want scanf to allocate the memory on your behalf and place the scanned string in the provided buffer https://man7.org/linux/man-pages/man3/scanf.3.html – Scott M Mar 27 '22 at 22:24