Here is a brief summary:
You could use macros to stringify the maximum length of the string to input, not the buffer length, but this is very cumbersome and fragile as the macro MAX_BUF_LEN is not necessarily macro and might not expand to a single decimal number without a suffix (eg: #define MAX_BUF_LEN 32U or #define MAX_BUF_LEN (32))
you could construct the format string in a buffer with snprintf and call scanf() with this buffer as the format string, but this solution is also very cumbersome and calling scanf() with an opaque format string is risky as the compiler cannot check the types of the arguments for consistency.
the scanf() format string "%31[^\n]" is intrinsically problematic too:
- the conversion will fail if there is a pending newline in the input stream (use
" %31[^\n]" to avoid this)
- there is no way to input an empty line
- the trailing newline will stay in the input stream after
scanf() returns, along with any remaining input if more than 31 bytes were input. Use " %31[^\n]%*[^\n]" to discard extra characters or " %31[^\n]%*1[\n]" to consume the newline, but you cannot have both at the same time with a single scanf() format.
I strongly suggest you avoid scanf() and use fgets() for this type on input, or better, a custom function modelled after get_string() for the cs50 library or something simpler like this:
#include <stdio.h>
// read a full string of input into a fixed length destination array
// return the number of characters read into the destination array
// truncation occurred if the return value is >= size.
// immediate end of file causes a return value of -1
int get_string(const char *prompt, char *buf, size_t size) {
size_t i;
int c;
if (prompt) {
printf("%s: ");
fflush(stdout);
}
for (i = 0; (c = getchar()) != EOF && c != '\n'; i++) {
if (i + 1 < size)
buf[i] = (char)c;
}
if (i < size)
buf[i] = '\0';
else
if (size > 0)
buf[size - 1] = '\0';
return (i == 0 && c == EOF) ? -1 : (int)i;
}
int main(void) {
char buffer[MAX_BUF_LEN + 1];
int len = get_string("Enter string", buffer, sizeof buffer);
printf("length is %d\n", len);
printf("string is >%s<\n", buffer);
return 0;
}
scanfand usefgetsinstead:fgets(buf, sizeof buf, stdin);scanf()is not actually required. I suspect it might be, for teaching purposes not about input reading but about macro useage. Is your programming class currently more concerned with input or with macros?