C crea bytes extra en el búfer

He estado jugando con C hoy y no entiendo la diferencia en los resultados cuando comento el tercer búfer en este código:

#include  #include  #include  void main() { unsigned char letters[10]; memset(letters, 0x00, 10); memset(letters, 0x41, 10); printf(letters); printf(" Total buffer len: %d bytes\n",strlen(letters)); char nletters[10]; memset(nletters, 0x00, 10); memset(nletters, 0x42, 10); printf(nletters); printf(" Total buffer len: %d bytes\n",strlen(nletters)); int nums[10]; memset(nums, 0x00, 10); memset(nums, 0x43, 10); printf(nums); printf(" Total buffer len: %d bytes\n",strlen(nums)); return 0; } 

La diferencia es que los comentarios se eliminan alrededor del búfer nums:

 AAAAAAAAAA 7ǝ U Total buffer len: 16 bytes BBBBBBBBBBAAAAAAAAAA 7ǝ U Total buffer len: 26 bytes 

Y con el buffer dejado en:

 AAAAAAAAAA Total buffer len: 10 bytes BBBBBBBBBBAAAAAAAAAA Total buffer len: 20 bytes CCCCCCCCCC  U Total buffer len: 14 bytes 

Lo que no entiendo es:

  1. ¿Cómo puede el comentar el tercer búfer afectar el tamaño de los otros?

  2. ¿Cuáles son los bytes adicionales al final de los búferes y cómo puedo perderlos / gestionarlos (si elijo concatenar los búferes)?

  3. ¿Por qué las diferencias en el tamaño del búfer impreso y el tamaño inicializado no son consistentes cuando elijo si comentar el tercer búfer?

  4. El búfer 2 se supone que es de 10 bytes, ¿por qué es 20? No quiero que sean 20, solo pedí 10. No creo que sea irrazonable.

char cadenas de caracteres en C realmente se llaman cadenas de bytes terminadas en nulo . Ese bit terminado en nulo es importante, y todas las funciones de cadena lo buscan para saber cuándo termina la cadena.

Si pasa una cadena no terminada a una función de cadena, saldrá de los límites y eso conducirá a un comportamiento indefinido .

El terminador es igual a cero, ya sea el entero 0 o el carácter '\0' .

Y, por supuesto, este carácter de terminador nulo necesita espacio en la cadena. Eso significa que una cadena de 10 caracteres debe tener espacio para que 11 se ajusten al terminador.

Lo simple primero se vería como

 char letters[11] = { 0 }; // Space for ten character plus terminator // The above definition also initializes all elements in the array to zero, // which is the terminator character memset(letters, 'A', 10); // Set the ten first characters to the letter 'A' printf("%s", letters); // Never print a data string directly using printf's first parameter. printf(" Total buffer len: %d bytes\n", strlen(letters)); 

Tenga en cuenta el cambio a printf . Esto se debe a que si alguna vez obtiene la entrada de la cadena de un usuario, pasarla directamente como la cadena de formato a printf es un agujero de seguridad increíblemente malo. Si la cadena contiene código de formato pero no hay argumentos, esto podría conducir a un comportamiento indefinido .

También tenga en cuenta que cambié el número mágico 0x41 al carácter ASCII al que corresponde. Los números mágicos son un mal hábito que hace que el código sea más difícil de leer, entender y mantener.

Prueba esto:

 memset(letters, 0x00, 10); memset(letters, 0x41, 9); /* <--- see the array size minus one there */ 

eso hará que el printf(3) funcione correctamente, pero imprimiendo solo una lista de nueve A s. Como se explicó en otras respuestas, esto tiene que ver con la pesadilla de los progtwigdores de C para terminar de forma nula las cadenas creadas a mano. Por esa razón es más común usar las funciones .

En otro lugar, se desaconseja el uso del primer parámetro de printf() sin una cadena literal, como en el caso de que la cadena tuviera un carácter % , que se interpretaría como un descriptor de formato, y se habría encontrado con un comportamiento más indefinido, de nuevo .