scanf("%[^\n]s",a) vs gets(a)

niko picture niko · Nov 18, 2011 · Viewed 58.4k times · Source

I have been told that scanf should not be used when user inputs a string. Instead, go for gets() by most of the experts and also the users on StackOverflow. I never asked it on StackOverflow why one should not use scanf over gets for strings. This is not the actual question but answer to this question is greatly appreciated.

Now coming to the actual question. I came across this type of code -

scanf("%[^\n]s",a); 

This reads a string until user inputs a new line character, considering the white spaces also as string.

Is there any problem if I use

scanf("%[^\n]s",a);

instead of gets?

Is gets more optimized than scanf function as it sounds, gets is purely dedicated to handle strings. Please let me know about this.

Update

This link helped me to understand it better.

Answer

sarnold picture sarnold · Nov 18, 2011

gets(3) is dangerous and should be avoided at all costs. I cannot envision a use where gets(3) is not a security flaw.

scanf(3)'s %s is also dangerous -- you must use the "field width" specifier to indicate the size of the buffer you have allocated. Without the field width, this routine is as dangerous as gets(3):

char name[64];
scanf("%63s", name);

The GNU C library provides the a modifier to %s that allocates the buffer for you. This non-portable extension is probably less difficult to use correctly:

   The GNU C library supports a nonstandard extension that
   causes the library to dynamically allocate a string of
   sufficient size for input strings for the %s and %a[range]
   conversion specifiers.  To make use of this feature, specify
   a as a length modifier (thus %as or %a[range]).  The caller
   must free(3) the returned string, as in the following
   example:

       char *p;
       int n;

       errno = 0;
       n = scanf("%a[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 only necessary to call
   free(3) if the scanf() call successfully read a string.