Longitud máxima de cadena usando scanf -> ANSI C

Yo tengo:

#define MAX_STR_LEN 100 

y quiero ponerlo en el patrón scanf para poder controlar la longitud de la cadena:

 scanf("%100[^\n]s",sometext) 

Lo intenté:

 scanf("%MAX_STR_LEN[^\n]s",sometext) scanf("%"MAX_STR_LEN"[^\n]s",sometext) scanf("%",MAX_STR_LEN,"[^\n]s",sometext) 

Y no funcionó. Solo quiero evitar el desbordamiento del búfer ya que “sometext” está asignado con malloc(MAX_STR_LEN)

¿Algunas ideas?

No estaba contento con ninguna de estas soluciones, así que investigué más y descubrí la macrocorificación de GNC GCC

que se puede usar como:

 #define XSTR(A) STR(A) #define STR(A) #A #define MAX_STR_LEN 100 scanf("%"XSTR(MAX_STR_LEN)"[^\n]s", sometext) 

¿Tal vez VS2010 ofrece algo similar?

Solo quiero evitar el desbordamiento de búfer

Entonces no use scanf() . En absoluto.

Si está escaneando líneas de texto, no #define MAX_STR tampoco. Puede haz LINE_MAX en (si se dirige a sistemas POSIX compatibles):

 char buf[LINE_MAX]; fgets(buf, sizeof(buf), stdin); 

debería hacer el truco.

Como casi todos dicen, es mejor usar fgets(..., stdin) para manejar este problema.

En el siguiente enlace, he sugerido una técnica segura y correcta que le permite reemplazar scanf() por un método más seguro, por medio de una macro sólida:

Una macro que reemplaza de forma segura a scanf ()

La macro que he propuesto (trabajando con comstackdores C99 compatibles) es safe_scanf() , como se muestra en el siguiente progtwig:

 #include  #define safe_scanf(fmt, maxb, ...) { \ char buffer[maxb+1] = { [maxb - 1] = '\0' }; \ fgets(buffer, maxb+1, stdin); \ if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \ while(getchar() != '\n') \ ; \ sscanf(buffer, fmt, __VA_ARGS__); \ } #define MAXBUFF 20 int main(void) { int x; float f; safe_scanf("%d %g", MAXBUFF+1, &x, &f); printf("Your input was: x == %d\t\tf == %g", x, f); return 0; } 

MAXBUFF ajustar el valor de MAXBUFF según sus necesidades …
Aunque la macro safe_scanf() es bastante sólida,
hay algunas deficiencias en el uso del enfoque macro:
Falta la verificación de tipo para los parámetros, los valores de “retorno” faltantes (que apenas difieren de la función “verdadero” scanf() , que devuelve un int , con información valiosa para la comprobación de errores), y así sucesivamente.
Todos los problemas tienen solución, pero es parte de otro tema …

Tal vez, la solución más exacta es definir una función my_scanf() con un número variable de parámetros, invocando la biblioteca stdarg.h , conjunta a una combinación de fgets() y vsscanf() . Aquí tienes el código:

 #include  #include  int my_scanf(const char* fmt, const unsigned int maxbuff, ...) { va_list ptr; int ret; if (maxbuff <= 0) return EOF; /* Bad size for buffer[] */ char buffer[maxbuff+1]; buffer[maxbuff-1] = '\0'; /* Quick buffer cleaning... */ if (fgets(buffer, maxbuff+1, stdin) == NULL) return EOF; /* Error detected */ else { if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0')) /* Condition logically equivalent to: fgets() has not reached an '\n' */ while (getchar() != '\n') ; /* "Flushing" stdin... */ va_start(ptr, maxbuff); ret = vsscanf(buffer, fmt, ptr); va_end(ptr); return ret; } } #define MAXBUFF 20 int main(void) { int x; float z; int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z); printf("\nTest:\nx == %d\nz == %g\n scanfret == %d", x, z, scanf_ret); getchar(); return 0; } 

La función my_scanf () tiene el prototipo

 int my_scanf(const char* fmt, const int maxbuff, ...); 

Acepta una cadena de formato fmt que se comporta de la misma manera que cualquier otro scanf() -like does.
El segundo parámetro es la cantidad máxima de caracteres que se aceptarán de manera efectiva desde la entrada estándar (teclado).
El valor de retorno es un int , que es EOF si maxbuff no tiene sentido, o bien, se produjo algún error de entrada. Si se devuelve un valor no negativo, es el mismo que devolverían las funciones estándar sscanf() o vsscanf() .

Dentro de la función, maxbuff se incrementa en 1, porque fgets() deja espacio para un carácter '\ 0' adicional.
Los valores no positivos de maxbuff se descartan inmediatamente.
fgets() leerá una cadena que se lee desde stdin (teclado) con espacio para como máximo caracteres de maxbuff , incluyendo '\ n'.
Si el usuario ha ingresado una cadena muy larga, entonces se truncará, y es necesario algún tipo de mecanismo de "descarga" para descartar todos los caracteres al siguiente '\ n' ( ENTER ). Si no, la próxima lectura del teclado podría tener caracteres más antiguos, no deseados en absoluto.
La condición para "enjuagar" es que fgets() no ha llegado a '\ n' después de leer stdin .
Este es el caso si, y solo si, el buffer[maxbuff - 1] no es igual a '\ 0' ni '\ n'.
Compruébalo! )
Finalmente, se stdarg.h una combinación apropiada de macros stdarg.h y la función vsscanf() para procesar la lista de variables de parámetros.

Recomiende el enfoque de fgets(buffer, sizeof(buffer), stdin) .

Si aún desea usar scanf (), puede crear su formato en tiempo de ejecución.

 #define MAX_STR_LEN 100 char format[2 + sizeof(size_t)*3 + 4 + 1]; // Ugly magic # sprintf(format, " %%%zu[^\n]", (size_t) MAX_STR_LEN); scanf(format, sometext); 

o redefine MAX_STR_LEN para que sea una cadena

 #define MAX_STR_LEN "100" scanf(" %" MAX_STR_LEN "[^\n]", sometext); 

Todavía recomiendo los fgets() .
Observe que fgets() colocará los espacios iniciales y el \n nque arrastra en su memoria intermedia mientras que " %[^\n]" no lo hará.
Por cierto: los últimos en tus formatos probablemente no hagan lo que piensas.

Qué tal si

 scanf("%.*[^\n]s", MAX_STR_LEN, sometext)