diferencia de ancho fijo cadenas y cadenas terminadas en cero

gcc 4.4.4 c89

Me metí en una discusión reciente sobre “cadenas de ancho fijo” y “cadenas terminadas en cero”.

Cuando pienso en esto. Parecen ser lo mismo. Una cadena con una terminación nula.

es decir

char *name = "Joe bloggs"; 

Es una cadena de ancho fijo que no se puede cambiar. Y también tiene una terminación nula.

También en la discusión me dijeron que strncpy nunca debería usarse en ‘cadenas terminadas en cero’.

Muchas gracias por cualquier sugerencia,

El término “cadena de ancho fijo” generalmente se refiere a algo completamente diferente.

Una cadena de ancho fijo con N es una cadena de exactamente N caracteres, donde se garantiza la inicialización de todos los N caracteres. Si desea representar una cadena más corta, tiene que rellenar su cadena con cero caracteres al final. Debe agregar tantos caracteres cero como sea necesario para usar todos los N caracteres. Tenga en cuenta que si necesita almacenar una cadena de longitud exactamente N , una cadena de ancho fijo no tendrá ningún carácter de cero al final. Es decir, en general, las cadenas de ancho fijo no terminan en cero.

¿Cuál es el propósito de esto? El propósito de esto es guardar 1 carácter al almacenar la cadena de la longitud máxima posible. Si está utilizando cadenas de ancho fijo de ancho N , entonces necesita exactamente N caracteres para representar una cadena de longitud N Compare eso con las cadenas normales terminadas en cero, que requerirían un carácter N + 1 (carácter adicional para el terminador cero).

¿Por qué se rellena con ceros al final? Se rellena con ceros para simplificar la comparación lexicográfica de cuerdas de ancho fijo. Simplemente compara todos los N caracteres hasta que llegues a la diferencia. Tenga en cuenta que uno puede usar absolutamente cualquier carácter para rellenar la cadena de ancho fijo hasta la longitud completa. Solo asegúrese de obtener el orden lexicográfico correcto. Sin embargo, usar cero caracteres para el relleno es una buena opción.

¿Cuándo es útil? Muy raramente Los ahorros proporcionados por las cadenas de ancho fijo rara vez son importantes en el procesamiento de cadenas genéricas: estos ahorros son demasiado pequeños y solo se producen en los casos en que la cadena utiliza todo el ancho. Pero podrían llegar a ser útiles en algunos casos específicos.

¿De dónde viene todo esto? Un ejemplo clásico de una “cadena de ancho fijo” es un campo de nombre de archivo ancho de 14 caracteres en alguna versión antigua del sistema de archivos Unix. Se representó mediante una matriz de 14 caracteres y se utilizó una representación de ancho fijo. En ese momento era importante guardar 1 carácter en el nombre del archivo de longitud completa (todos los 14 caracteres).

Ahora a strncpy . La función strncpy se introdujo específicamente para inicializar los campos de nombre de archivo de 14 caracteres de ancho en ese sistema de archivos. La función strncpy se creó específicamente para generar una cadena válida de ancho fijo: realiza la conversión de una cadena terminada en cero en una cadena de ancho fijo. Desafortunadamente, se le dio un nombre engañoso, razón por la cual muchas personas hoy en día lo confunden con una función de copia “segura” para cadenas terminadas en cero. Este último es un entendimiento totalmente incorrecto del propósito y la funcionalidad de strncpy .

Usar literales de cadena para representar cadenas de ancho fijo (como en su ejemplo) no es una buena idea, ya que los literales de cadena siempre agregan un carácter de cero al final, y las cadenas de ancho fijo no necesariamente lo hacen. Así es como se pueden inicializar un grupo de cadenas de ancho fijo en un progtwig C

 char fw_string1[7] = { 'T', 'h', 'i', 's', ' ', 'i', 's' }; char fw_string2[7] = { 's', 't', 'r', 'i', 'n', 'g' }; char fw_string3[7] = { 'H', 'e', 'l', 'l', 'o' }; 

Todas las matrices tienen el mismo número de elementos: 7. Tenga en cuenta que la primera cadena no está terminada en cero, mientras que el rest está rellenado con cero. La conversión de una cadena “normal” en una de ancho fijo se verá de la siguiente manera

 char fw_string4[7]; strncpy(fw_string4, "Hi!", 7); 

En este caso, la función strncpy se usa exactamente para lo que fue diseñada.

Tenga en cuenta también que, aparte de la función de conversión strncpy , la biblioteca estándar no proporciona prácticamente ningún medio para trabajar con cadenas de ancho fijo. Básicamente, debe tratarlos como matrices de caracteres en bruto e implementar manualmente cualquier operación de nivel superior. La mayoría de las operaciones básicas se implementarán naturalmente mediante funciones del grupo mem... memcmp , por ejemplo, implementará la comparación.

PS En realidad, teniendo en cuenta el comentario de caf, en el lenguaje C se pueden usar literales de cadena para inicializar cadenas de ancho fijo, ya que el lenguaje C permite que el inicializador literal sea un carácter más largo que la matriz (es decir, en C está bien, si el cero final) no encaja en la matriz). Así, lo anterior se puede reescribir de manera equivalente como

 char fw_string1[7] = "This is"; char fw_string2[7] = "string"; char fw_string3[7] = "Hello"; 

Tenga en cuenta que fw_string1 aún no está terminada en cero en este caso.

En primer lugar, creo que te refieres a una cadena de longitud fija, no a una cadena fija.

En segundo lugar, lo anterior es una cadena terminada en nulo. No debe cambiarse debido a su definición como una constante literal.

AFAIK C no tiene ninguna “cadena de longitud fija” real. En el mejor de los casos, podría definir un búfer de tamaño N y colocar no más de N-1 caracteres, donde colocar más sería un error y olvidar el terminador nulo puede ser un error.

En cuanto a strncpy, lo que hace es copiar el número especificado de caracteres y cero los demás. Esto significa que si el destino no es lo suficientemente largo, estaría escribiendo más allá del espacio disponible o no tendría un terminador nulo en su cadena, lo que provocaría errores cuando intente utilizar la cadena.

No estoy muy seguro acerca del término “corregir cadena de ancho”. Dependiendo de la función, las cadenas necesitan o no necesitan un final \ 0. Las funciones como strlen y strcpy necesitan trabajar en cadenas terminadas en \ 0 para saber cuándo parar. Las funciones como strncpy no necesitan que la cadena fuente esté terminada en \ 0 ya que un argumento indica cuántos caracteres se deben copiar.

Cuando declara el nombre mientras lo hace, el contenido del nombre al que se apunta se almacena en la memoria de solo lectura y no se puede modificar; sin embargo, puede usar ‘nombre’ en las funciones de C que no modifican el contenido, por ejemplo, strlen (nombre) o cuando se usa como fuente:

 char mycopy[32]; strcpy( mycopy, name );