tampon soluciones solucion sistemas resueltos reguladoras henderson hemoglobina hasselbach fosfato fisiologicos ejercicios ecuacion capacidad amortiguadores amortiguadora c standards c-standard-library

soluciones - tampon fosfato



¿Los buffers de garantía del estándar C no se tocan más allá de su terminador nulo? (7)

En los diversos casos en que se proporciona un búfer a las numerosas funciones de cadena de la biblioteca, ¿se garantiza que el búfer no se modificará más allá del terminador nulo? Por ejemplo:

char buffer[17] = "abcdefghijklmnop"; sscanf("123", "%16s", buffer);

¿Se requiere que el buffer sea ​​igual a "123/0efghijklmnop" ?

Otro ejemplo:

char buffer[10]; fgets(buffer, 10, fp);

Si la línea de lectura tiene solo 3 caracteres, ¿se puede estar seguro de que el sexto carácter es el mismo que antes de llamar a fgets?


¿Se garantiza que el búfer no se modificará más allá del terminador nulo?

No, no hay garantía.

¿Se requiere que el búfer sea igual a "123 / 0efghijklmnop"?

Sí. Pero eso es solo porque has usado los parámetros correctos para tus funciones relacionadas con cadenas. En caso de desordenar la longitud del búfer, ingresar modificadores a sscanf y sscanf , entonces el programa se compilará. Pero lo más probable es que falle durante el tiempo de ejecución.

Si la línea de lectura tiene solo 3 caracteres, ¿se puede estar seguro de que el sexto carácter es el mismo que antes de llamar a fgets?

Sí. Una vez que fgets() calcula que tiene una cadena de entrada de 3 caracteres, almacena la entrada en el búfer proporcionado, y no le importa el restablecimiento del espacio provisto.


¿Se requiere que el búfer sea igual a "123 / 0efghijklmnop"?

Aquí el buffer solo consiste en 123 cadenas garantizadas que terminan en NUL.

Sí, la memoria asignada para el buffer matriz no se desasignará, sin embargo, se está asegurando de que la restricción del buffer cadena pueda tener solo 16 elementos de caracteres que puede leer en cualquier momento. Ahora depende de si escribe solo un solo carácter o máximo lo que el buffer puede tomar.

Por ejemplo:

char buffer[4096] = "abc";`

en realidad hace algo a continuación,

memcpy(buffer, "abc", sizeof("abc")); memset(&buffer[sizeof("abc")], 0, sizeof(buffer)-sizeof("abc"));

El estándar insiste en que si se inicializa alguna parte de la matriz de caracteres, eso es todo en lo que consiste en cualquier momento hasta que se cumpla su límite de memoria.


Cada byte individual en el búfer es un objeto. A menos que alguna parte de la descripción de la función de sscanf o fgets mencione la modificación de esos bytes, o incluso implique que sus valores puedan cambiar, por ejemplo, al indicar que sus valores no están especificados, entonces se aplica la regla general: (énfasis mío)

6.2.4 Duraciones de almacenamiento de objetos.

2 [...] Un objeto existe, tiene una dirección constante y conserva su último valor almacenado durante su vida útil . [...]

Es este mismo principio el que garantiza que

#include <stdio.h> int a = 1; int main() { printf ("%d/n", a); printf ("%d/n", a); }

intenta imprimir 1 dos veces. Aunque a es global, printf puede acceder a variables globales, y la descripción de printf no menciona la modificación de a .

Ni la descripción de fgets ni la de sscanf mencionan la modificación de los buffers más allá de los bytes que se suponía que debían escribirse (excepto en el caso de un error de lectura), por lo que esos bytes no se modifican.


Depende de la función en uso (y en menor medida su implementación). sscanf comenzará a escribir cuando encuentre su primer carácter que no sea un espacio en blanco, y continuará escribiendo hasta su primer carácter de espacio en blanco, donde agregará un 0 final y regresará. Pero una función como strncpy (famoso) apaga el resto del búfer.

Sin embargo, no hay nada en el estándar C que ordene cómo se comportan estas funciones.


El borrador de la norma C99 no establece explícitamente lo que debería suceder en esos casos, pero si considera múltiples variaciones, puede demostrar que debe funcionar de cierta manera para que cumpla con la especificación en todos los casos.

La norma dice:

% s - Coincide con una secuencia de caracteres que no son espacios en blanco.252)

Si no está presente un modificador de longitud l, el argumento correspondiente será un puntero al elemento inicial de una matriz de caracteres lo suficientemente grande como para aceptar la secuencia y un carácter nulo de terminación, que se agregará automáticamente.

Aquí hay un par de ejemplos que muestran que debe funcionar de la manera que usted propone cumplir con el estándar.

Ejemplo A:

char buffer[4] = "abcd"; char buffer2[10]; // Note the this could be placed at what would be buffer+4 sscanf("123 4", "%s %s", buffer, buffer2); // Result is buffer = "123/0" // buffer2 = "4/0"

Ejemplo B:

char buffer[17] = "abcdefghijklmnop"; char* buffer2 = &buffer[4]; sscanf("123 4", "%s %s", buffer, buffer2); // Result is buffer = "123/04/0"

Tenga en cuenta que la interfaz de sscanf no proporciona suficiente información para saber realmente que eran diferentes. Por lo tanto, si el Ejemplo B debe funcionar correctamente, no debe alterar los bytes después del carácter nulo en el Ejemplo A. Esto se debe a que debe funcionar en ambos casos según este bit de especificación.

Así que, implícitamente , debe funcionar como usted indicó debido a la especificación.

Se pueden colocar argumentos similares para otras funciones, pero creo que se puede ver la idea de este ejemplo.

NOTA: Proporcionar límites de tamaño en el formato, como "% 16s", podría cambiar el comportamiento. Según la especificación, sería funcionalmente aceptable para sscanf poner a cero un búfer hasta sus límites antes de escribir los datos en el búfer. En la práctica, la mayoría de las implementaciones optan por el rendimiento, lo que significa que dejan el resto solo.

Cuando la intención de la especificación es hacer este tipo de reducción a cero, generalmente se especifica explícitamente. Strncpy es un ejemplo. Si la longitud de la cadena es menor que la longitud máxima del búfer especificada, llenará el resto del espacio con caracteres nulos. El hecho de que esta misma función de "cadena" pueda devolver una cadena no terminada también hace que esta sea una de las funciones más comunes para que las personas rueden su propia versión.

En cuanto a fgets, podría surgir una situación similar. El único problema es que la especificación establece explícitamente que si no se lee nada, el búfer permanece intacto. Una implementación funcional aceptable podría evitar esto al verificar si hay al menos un byte para leer antes de poner a cero el búfer.


El estándar es algo ambiguo en esto, pero creo que una lectura razonable es que la respuesta es: sí, no está permitido escribir más bytes en el búfer de lo que lee + nulo. Por otro lado, una lectura / interpretación más estricta del texto podría concluir que la respuesta es no, no hay garantía. Esto es lo que dice un borrador disponible públicamente sobre fgets .

char *fgets(char * restrict s, int n, FILE * restrict stream) ;

La función fgets lee a lo sumo uno menos que el número de caracteres especificados por n en el flujo al que apunta el stream en la matriz apuntada por s . No se leen caracteres adicionales después de un carácter de nueva línea (que se conserva) o después del final del archivo. Se escribe un carácter nulo inmediatamente después de la última lectura del carácter en la matriz.

La función fgets devuelve s si tiene éxito. Si se encuentra el final del archivo y no se han leído caracteres en la matriz, el contenido de la matriz permanece sin cambios y se devuelve un puntero nulo. Si se produce un error de lectura durante la operación, el contenido de la matriz es indeterminado y se devuelve un puntero nulo.

Existe una garantía acerca de cuánto se supone que debe leer en la entrada, es decir, deje de leer en línea nueva o EOF y no lea más de n-1 bytes. Aunque no se dice nada explícitamente acerca de cuánto se puede escribir en el búfer, el conocimiento común es que el parámetro n fgets se usa para evitar los desbordamientos del búfer. Es un poco extraño que el estándar use el término ambiguo de lectura , lo que puede no necesariamente implicar que no gets puede escribir en el búfer más de n bytes, si desea conocer la terminología que utiliza. Pero tenga en cuenta que la misma terminología de "lectura" se utiliza para ambos problemas: el límite n e y el límite EOF / newline. Entonces, si interpreta la "lectura" relacionada con n como un límite de escritura en el búfer, entonces [por coherencia] puede / debe interpretar la otra "lectura" de la misma manera, es decir, no escribir más de lo que lee cuando la cadena es más corta que el amortiguador

Por otro lado, si distingue entre los usos de la frase-verbo "leer en" (= "escribir") y solo "leer", entonces no puede leer el texto del comité de la misma manera. Se le garantiza que no "leerá" (= "escribir en") la matriz con más de n bytes, pero si la cadena de entrada termina antes con una nueva línea o EOF, solo se le garantiza el resto (de la entrada) no se "leerá", pero si eso implica que no se "leerá" (= "escrito en"), el búfer no está claro bajo esta lectura más estricta. El problema crucial es que la palabra clave está "en", que se elimina, por lo que el problema es si la finalización entregada por mí entre paréntesis en la siguiente cita modificada es la interpretación deseada:

No se leen caracteres adicionales [en la matriz] después de un carácter de nueva línea (que se mantiene) o después del final del archivo.

Francamente, una sola condición posterior declarada como una fórmula (y sería bastante breve en este caso) hubiera sido mucho más útil que la vergüenza que cité ...

No puedo molestarme en intentar analizar su información sobre la familia *scanf , porque sospecho que va a ser aún más complicado dadas todas las otras cosas que suceden en esas funciones; su redacción para fscanf tiene aproximadamente cinco páginas ... Pero sospecho que se aplica una lógica similar.


No hay ninguna garantía de la norma, por lo que se recomienda utilizar las funciones sscanf y fgets (con respecto al tamaño del búfer) como se muestra en su pregunta (y el uso de fgets se considera preferible en comparación con gets ).

Sin embargo, algunas funciones estándar usan terminador nulo en su trabajo, por ejemplo, strlen (pero supongo que usted pregunta acerca de la modificación de la cadena)

EDITAR:

En tu ejemplo

fgets(buffer, 10, fp);

los caracteres intactos después de 10-th están garantizados (el contenido y la longitud del buffer no serán considerados por fgets )

EDIT2:

Además, al usar fgets tenga en cuenta que ''/n'' se almacenará en los buffers. p.ej

"123/n/0fghijklmnop"

en lugar de lo esperado

"123/0efghijklmnop"