2011-03-02 8 views
6

¿Se permite un puntero NULL como cadena para almacenar el resultado en una llamada al sscanf? No encuentro nada al respecto en ninguna documentación, pero parece estar funcionando bien. Lo mismo con scanf.NULL arg permitido a sscanf?

Ejemplo:

int main(int arc, char* argv[]) 
{ 
    char* s = NULL; 
    sscanf("Privjet mir!", "%s", s); 
    printf("s: %s\n", s); 
    return 0; 
} 

de salida: s: (null)

Respuesta

6

No:

ajusta con una secuencia de no blancas-espacio caracteres; el siguiente puntero debe ser un puntero a la matriz de caracteres que es suficiente para contener la secuencia de entrada y el carácter nulo de terminación ('\ 0'), que se agrega automáticamente. La cadena de entrada se detiene en el espacio en blanco o en el ancho máximo del campo, lo que ocurra primero.

(http://linux.die.net/man/3/sscanf)

+0

Esta respuesta también nos enseña que la prohibición de null no necesita mencionar explícitamente la palabra "null".Establecer que algo debe ser "un puntero a " implícitamente prohíbe el nulo. – Lii

1

La página de manual dice que, al utilizar %s, el argumento debe ser un puntero con espacio suficiente para la cuerda y \0. Así que supongo que el comportamiento en su caso no está definido. Puede funcionar, también puede bloquear o dañar la memoria y causar problemas más adelante.

1

No, esto no está permitido. sscanf% s espera una char * apuntando a un búfer grande suficiente, printf% s quiere un búfer nul char *. Cualquier otra cosa da como resultado un comportamiento indefinido. (Y eso significa que algunas implementaciones pueden detectar y manejar un puntero nulo, en cierto modo, otras implementaciones no)

1

no he encontrado nada en la norma relativa a NULL explícita y *printf/*scanf.

supongo que este es un comportamiento indefinido , ya que cuenta como pasando un argumento que no es coherente con el especificador de formato (§7.19.6.1 párrafo 13, §7.19.6.2 párrafo 13): %s significa que una va a pasar un puntero al primer elemento de una matriz de caracteres (lo suficientemente grande para la cadena adquirida para *scanf, que contiene una cadena terminada en NUL para *printf) y pasar NULL no cumple este requisito.


1. En este caso UB muestra como "simplemente haciendo caso omiso de la adquisición" y "la impresión (nulo)", en otras plataformas que pueden resultar en aviones que caían del cielo o la costumbre nasal demons.

-2

Asignar la memoria a s. Asignar s a la matriz de caracteres. Luego ejecuta el programa. A continuación funcionará.

int main(int arc, char* argv[]) 
{ 
    char s[100]; 
    sscanf("Privjet mir!", "%[^\t]s", s); 
    printf("s: %s\n", s); 
    return 0; 
} 
+0

Realmente no responde mi pregunta ... – Lii

4

Como es mencionado por las otras respuestas NULL no es válida para pasar a sscanf como un argumento adicional.

http://www.cplusplus.com/reference/cstdio/sscanf dice de argumentos adicionales:

Dependiendo de la cadena de formato, la función puede esperar que una secuencia de argumentos adicionales, cada uno con un puntero de almacenamiento asignado en la interpretación de los personajes extraídos se almacena con el tipo apropiado.

For the %s specifier these extracted characters are:

Cualquier número de caracteres no está en blanco, con parada en el primer carácter espacios que se encuentren. Un carácter nulo de terminación se agrega automáticamente al final de la secuencia almacenada.

Por lo tanto, cuando se almacenan los "caracteres que no son de espacios en blanco" y "carácter nulo de terminación", habrá una segfault. ¿Qué es exactamente lo que Visual Studio rendirá (se puede probar que esta falla en http://webcompiler.cloudapp.net/):

enter image description here

Ahora por lo que los compiladores no Visual Studio, el código de extracción de libc para la %s especificador: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 tiene el líder comentario: /* We might have to handle the allocation ourselves */ esto es porque:

la biblioteca GNU C apoyó el especificador de conversión asignación dinámica (como una extensión no estándar) a través del carácter a. Esta característica parece estar presente al menos desde glibc 2.0.
Desde la versión 2.7, glibc también proporciona el modificador m con el mismo propósito que el modificador a.

[Source]

Así pues extractos libc a un buffer construidos internamente para sscanf y posteriormente se comprueba que el parámetro de búfer no tiene indicadores establecidos antes de asignarlo, nunca va a escribir caracteres a un parámetro NULL búfer.

No puedo dejar de insistir en que esto no es estándar, y no se garantiza que se conserve incluso entre actualizaciones menores de la biblioteca. Un mucho mejor manera de hacer esto es utilizar el * sub-especificador que:

indica que los datos se debe leer de la corriente pero ignorado (es decir, no se almacena en la ubicación señalado por un argumento) .

[Source]

Esto podría lograrse así por ejemplo:

s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s); 

Obviamente el verdadero-rama del ternario es un no-op, pero he incluido con la expectativa de que se esperaban otros datos para leer de la cadena.