¿Cómo se convierte una matriz de bytes en una cadena hexadecimal en C?


88

Yo tengo:

uint8 buf[] = {0, 1, 10, 11};

Quiero convertir la matriz de bytes en una cadena de modo que pueda imprimir la cadena usando printf:

printf("%s\n", str);

y obtener (los dos puntos no son necesarios):

"00:01:0A:0B"

Cualquier ayuda será muy apreciada.


buf[i]debe ser fundido a unsigned char, o se desborde si buf[i] > 127, es decir:buf_ptr += sprintf(buf_ptr, "%02X", (unsigned char)buf[i]);
whatacold

Respuestas:


93
printf("%02X:%02X:%02X:%02X", buf[0], buf[1], buf[2], buf[3]);

de una manera más genérica:

int i;
for (i = 0; i < x; i++)
{
    if (i > 0) printf(":");
    printf("%02X", buf[i]);
}
printf("\n");

para concatenar a una cadena, hay algunas formas de hacer esto ... probablemente mantendría un puntero al final de la cadena y usaría sprintf. También debe realizar un seguimiento del tamaño de la matriz para asegurarse de que no sea más grande que el espacio asignado:

int i;
char* buf2 = stringbuf;
char* endofbuf = stringbuf + sizeof(stringbuf);
for (i = 0; i < x; i++)
{
    /* i use 5 here since we are going to add at most 
       3 chars, need a space for the end '\n' and need
       a null terminator */
    if (buf2 + 5 < endofbuf)
    {
        if (i > 0)
        {
            buf2 += sprintf(buf2, ":");
        }
        buf2 += sprintf(buf2, "%02X", buf[i]);
    }
}
buf2 += sprintf(buf2, "\n");

Gracias Mark, mi problema es un poco más complicado. De hecho, tengo un búfer con una longitud de X bytes. Esperaba encontrar una forma genérica de hacer esto para X bytes y tener una cadena como resultado.
Steve Walsh

Recientemente actualizado para agregar código para manejar cualquier número de bytes ... asumiendo que x es la longitud.
Mark Synowiec

Gracias de nuevo Mark, pero lo que me pareció más complicado para este problema es cómo imprimir esto en una cadena.
Steve Walsh

5
printf("%02X", (unsigned char)buf[i]);debe usarse ya que el original causará un desbordamiento de caracteres sin firmar
easytiger

3
¿Por qué no printf("%02hhX", buf[i])?
Hintron

32

Para completar, también puede hacerlo fácilmente sin llamar a ninguna función de biblioteca pesada (sin snprintf, sin strcat, ni siquiera memcpy). Puede ser útil, digamos, si está programando algún microcontrolador o kernel del sistema operativo donde libc no está disponible.

No hay nada realmente elegante, puedes encontrar un código similar si lo buscas en Google. Realmente no es mucho más complicado que llamar a snprintf y mucho más rápido.

#include <stdio.h>

int main(){
    unsigned char buf[] = {0, 1, 10, 11};
    /* target buffer should be large enough */
    char str[12];

    unsigned char * pin = buf;
    const char * hex = "0123456789ABCDEF";
    char * pout = str;
    int i = 0;
    for(; i < sizeof(buf)-1; ++i){
        *pout++ = hex[(*pin>>4)&0xF];
        *pout++ = hex[(*pin++)&0xF];
        *pout++ = ':';
    }
    *pout++ = hex[(*pin>>4)&0xF];
    *pout++ = hex[(*pin)&0xF];
    *pout = 0;

    printf("%s\n", str);
}

Aquí hay otra versión un poco más corta. Simplemente evita la variable de índice intermedio iy la duplicación del último código de caso (pero el carácter de terminación se escribe dos veces).

#include <stdio.h>
int main(){
    unsigned char buf[] = {0, 1, 10, 11};
    /* target buffer should be large enough */
    char str[12];

    unsigned char * pin = buf;
    const char * hex = "0123456789ABCDEF";
    char * pout = str;
    for(; pin < buf+sizeof(buf); pout+=3, pin++){
        pout[0] = hex[(*pin>>4) & 0xF];
        pout[1] = hex[ *pin     & 0xF];
        pout[2] = ':';
    }
    pout[-1] = 0;

    printf("%s\n", str);
}

A continuación se muestra otra versión para responder a un comentario que dice que utilicé un "truco" para saber el tamaño del búfer de entrada. En realidad, no es un truco, sino un conocimiento de entrada necesario (necesita saber el tamaño de los datos que está convirtiendo). Hice esto más claro extrayendo el código de conversión a una función separada. También agregué un código de verificación de límites para el búfer de destino, que no es realmente necesario si sabemos lo que estamos haciendo.

#include <stdio.h>

void tohex(unsigned char * in, size_t insz, char * out, size_t outsz)
{
    unsigned char * pin = in;
    const char * hex = "0123456789ABCDEF";
    char * pout = out;
    for(; pin < in+insz; pout +=3, pin++){
        pout[0] = hex[(*pin>>4) & 0xF];
        pout[1] = hex[ *pin     & 0xF];
        pout[2] = ':';
        if (pout + 3 - out > outsz){
            /* Better to truncate output string than overflow buffer */
            /* it would be still better to either return a status */
            /* or ensure the target buffer is large enough and it never happen */
            break;
        }
    }
    pout[-1] = 0;
}

int main(){
    enum {insz = 4, outsz = 3*insz};
    unsigned char buf[] = {0, 1, 10, 11};
    char str[outsz];
    tohex(buf, insz, str, outsz);
    printf("%s\n", str);
}

1
No es un truco, simplemente una constante. En el contexto de la pregunta, está claro que la longitud de la fuente que queremos convertir a hexadecimal es bien conocida (podría haber puesto algunos 4 codificados en lugar de sizeof). En el caso general, la función debe llamarse en alguna entrada de longitud conocida y el búfer de destino tiene 3 veces + 1 bytes disponibles. Esto debe ser garantizado por la persona que llama, no hay ninguna razón para que la función de conversión realice esa tarea. Llamar a strlen () puede ser una forma de encontrar el tamaño de la fuente en algunos casos, pero no siempre. ¿Qué pasa si el número para convertir a hexadecimal contiene ceros?
kriss

Inspirado por su función, escribí una versión que también devuelve el número de bytes escritos en el búfer de salida, similar a snprintf, etc. gist.github.com/cellularmitosis/0d8c0abf7f8aa6a2dff3
Jason Pepas

Creo que debería hacer que su búfer de salida tenga el tamaño correcto automáticamente usando char str [sizeof (buf) * 3 + 1];
Cecil Ward

También muchos más concursos te protegerían. Por ejemplo, "const unsigned char const * p" para que pueda asegurarse de que los búferes de entrada no estén escritos. Uno hace que la dirección (o 'puntero') sea constante o variable, y el otro hace que la memoria en esa dirección sea de solo lectura o no. A menudo evita que se confundan los consejos. Y también ayudaría tener nombres significativos que documenten qué búferes y punteros son para entrada y salida.
Cecil Ward

@Cecil War: a menos que mi código sea falso, el uso de const no protegerá mucho, excepto cuando diga mezclar punteros o usar el mismo puntero para entrada y salida (ok, aún es posible). Pero también ayudará al compilador a optimizar el código. Incluso mejor sería usar también la palabra clave restrict (lástima que C99 no C ++, pero a menudo existe como una extensión del compilador). ¿Qué quieres más significativo como llamar al búfer de entrada iny al búfer de salida out? También podría optar por usar una cadena y devolver una copia en lugar de proporcionar un búfer de salida, en los optimizadores modernos de C ++ son lo suficientemente buenos como para no importarles mucho.
kriss

15

Aquí hay un método que es mucho más rápido:

#include <stdlib.h>
#include <stdio.h>

unsigned char *     bin_to_strhex(const unsigned char *bin, unsigned int binsz,
                                  unsigned char **result)
{
  unsigned char     hex_str[]= "0123456789abcdef";
  unsigned int      i;

  if (!(*result = (unsigned char *)malloc(binsz * 2 + 1)))
    return (NULL);

  (*result)[binsz * 2] = 0;

  if (!binsz)
    return (NULL);

  for (i = 0; i < binsz; i++)
    {
      (*result)[i * 2 + 0] = hex_str[(bin[i] >> 4) & 0x0F];
      (*result)[i * 2 + 1] = hex_str[(bin[i]     ) & 0x0F];
    }
  return (*result);
}

int                 main()
{
  //the calling
  unsigned char     buf[] = {0,1,10,11};
  unsigned char *   result;

  printf("result : %s\n", bin_to_strhex((unsigned char *)buf, sizeof(buf), &result));
  free(result);

  return 0
}

3
Este código contiene un error que se manifiesta solo en entradas extrañas no imprimibles (no he tenido tiempo de profundizar exactamente en lo que está sucediendo matemáticamente). Intenta codificar el binario de hexadecimal ca9e3c972f1c5db40c0b4a66ab5bc1a20ca4457bdbe5e0f8925896d5ed37d726y saldrás ÌaÌe3cÌ72f1c5dÌ40c0b4a66Ìb5bÌ1Ì20cÌ4457bÌbÌ5Ì0Ì8Ì258Ì6Ì5Ìd37Ì726. Para solucionar esto, el bit dentro hex_strde la primera línea del ciclo for debe cambiarse a (input[i] >> 4) & 0x0Fcomo en la respuesta de @ kriss. Entonces funciona bien.
niemiro

Error: no comprueba el error malloc ().
Cecil Ward

Siempre es mejor usar caracteres sin firmar absolutamente en todas partes, ya que nadie quiere el riesgo de caracteres firmados (una característica de hardware de DEC PDP11 loca), y de esa manera no corre el riesgo de que las comparaciones firmadas salgan mal o los cambios a la derecha firmados corrompan los valores. En este caso, para ser justos, el código hace un & 0x0F a la defensiva en todas partes, lo que lo protege aquí.
Cecil Ward

El parámetro de entrada bin debe ser const unsigned char const * bin, para declarar la memoria como de solo lectura para los propósitos de esta rutina.
Cecil Ward

1
He integrado las propuestas de Cecil Ward, gracias por sus comentarios
Yannuth

14

Ya existen respuestas similares arriba, agregué esta para explicar cómo funciona exactamente la siguiente línea de código:

ptr += sprintf(ptr, "%02X", buf[i])

Es bastante complicado y no es fácil de entender, pongo la explicación en los comentarios a continuación:

uint8 buf[] = {0, 1, 10, 11};

/* Allocate twice the number of bytes in the "buf" array because each byte would
 * be converted to two hex characters, also add an extra space for the terminating
 * null byte.
 * [size] is the size of the buf array */
char output[(size * 2) + 1];

/* pointer to the first item (0 index) of the output array */
char *ptr = &output[0];

int i;

for (i = 0; i < size; i++) {
    /* "sprintf" converts each byte in the "buf" array into a 2 hex string
     * characters appended with a null byte, for example 10 => "0A\0".
     *
     * This string would then be added to the output array starting from the
     * position pointed at by "ptr". For example if "ptr" is pointing at the 0
     * index then "0A\0" would be written as output[0] = '0', output[1] = 'A' and
     * output[2] = '\0'.
     *
     * "sprintf" returns the number of chars in its output excluding the null
     * byte, in our case this would be 2. So we move the "ptr" location two
     * steps ahead so that the next hex string would be written at the new
     * location, overriding the null byte from the previous hex string.
     *
     * We don't need to add a terminating null byte because it's been already 
     * added for us from the last hex string. */  
    ptr += sprintf(ptr, "%02X", buf[i]);
}

printf("%s\n", output);

Lógica brillante. ¡Estaba buscando una hora para una elegante respuesta de cadena que no sea C ++ para este desafío!
Mark Terrill

6

Solo quería agregar lo siguiente, incluso si está un poco fuera del tema (no es el estándar C), pero me encuentro buscándolo a menudo y tropezando con esta pregunta entre los primeros resultados de búsqueda. La función de impresión del kernel de Linux printk, también tiene especificadores de formato para generar contenido de matriz / memoria "directamente" a través de un especificador de formato singular:

https://www.kernel.org/doc/Documentation/printk-formats.txt

Raw buffer as a hex string:
    %*ph    00 01 02  ...  3f
    %*phC   00:01:02: ... :3f
    %*phD   00-01-02- ... -3f
    %*phN   000102 ... 3f

    For printing a small buffers (up to 64 bytes long) as a hex string with
    certain separator. For the larger buffers consider to use
    print_hex_dump(). 

... sin embargo, estos especificadores de formato no parecen existir para el espacio de usuario estándar (s)printf.


4

Solución

La función btoxconvierte datos arbitrarios *bben una cadena sin terminar *xpde ndígitos hexadecimales:

void btox(char *xp, const char *bb, int n) 
{
    const char xx[]= "0123456789ABCDEF";
    while (--n >= 0) xp[n] = xx[(bb[n>>1] >> ((1 - (n&1)) << 2)) & 0xF];
}

Ejemplo

#include <stdio.h>

typedef unsigned char uint8;

void main(void) 
{
    uint8 buf[] = {0, 1, 10, 11};
    int n = sizeof buf << 1;
    char hexstr[n + 1];

    btox(hexstr, buf, n);
    hexstr[n] = 0; /* Terminate! */
    printf("%s\n", hexstr);
}

Resultado: 00010A0B.

En vivo: Tio.run .


1

Esta es una forma de realizar la conversión:

#include<stdio.h>
#include<stdlib.h>

#define l_word 15
#define u_word 240

char *hex_str[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};

main(int argc,char *argv[]) {


     char *str = malloc(50);
     char *tmp;
     char *tmp2;

     int i=0;


     while( i < (argc-1)) {
          tmp = hex_str[*(argv[i]) & l_word];
          tmp2 = hex_str[*(argv[i]) & u_word];

          if(i == 0) { memcpy(str,tmp2,1); strcat(str,tmp);}
          else { strcat(str,tmp2); strcat(str,tmp);}
          i++;
    }

    printf("\n*********  %s  *************** \n", str);

}

1

Versión de Yannith ligeramente modificada. Es solo que me gusta tenerlo como valor de retorno.

typedef struct {
   size_t len;
   uint8_t *bytes;
} vdata;

char* vdata_get_hex(const vdata data)
{
   char hex_str[]= "0123456789abcdef";

   char* out;
   out = (char *)malloc(data.len * 2 + 1);
   (out)[data.len * 2] = 0;
   
   if (!data.len) return NULL;
   
   for (size_t i = 0; i < data.len; i++) {
      (out)[i * 2 + 0] = hex_str[(data.bytes[i] >> 4) & 0x0F];
      (out)[i * 2 + 1] = hex_str[(data.bytes[i]     ) & 0x0F];
   }
   return out;
}


1

Esta función es adecuada cuando el usuario / llamador quiere que se coloque una cadena hexadecimal en una matriz / búfer de caracteres. Con una cadena hexadecimal en un búfer de caracteres, el usuario / llamador puede usar su propia macro / función para mostrarla o registrarla en cualquier lugar que desee (por ejemplo, en un archivo). Esta función también permite que la persona que llama controle el número de bytes (hexadecimales) para colocar en cada línea.

/**
 * @fn 
 * get_hex
 *
 * @brief 
 * Converts a char into bunary string 
 *
 * @param[in]   
 *     buf Value to be converted to hex string
 * @param[in]   
 *     buf_len Length of the buffer
 * @param[in]   
 *     hex_ Pointer to space to put Hex string into
 * @param[in]   
 *     hex_len Length of the hex string space
 * @param[in]   
 *     num_col Number of columns in display hex string
 * @param[out]   
 *     hex_ Contains the hex string
 * @return  void
 */
static inline void
get_hex(char *buf, int buf_len, char* hex_, int hex_len, int num_col)
{
    int i;
#define ONE_BYTE_HEX_STRING_SIZE   3
  unsigned int byte_no = 0;

  if (buf_len <= 0) {
      if (hex_len > 0) {
        hex_[0] = '\0';
      }
      return;
  }

  if(hex_len < ONE_BYTE_HEX_STRING_SIZE + 1)
  {
      return;
  }

  do {
         for (i = 0; ((i < num_col) && (buf_len > 0) && (hex_len > 0)); ++i )
         {
            snprintf(hex_, hex_len, "%02X ", buf[byte_no++] & 0xff);
            hex_ += ONE_BYTE_HEX_STRING_SIZE;
            hex_len -=ONE_BYTE_HEX_STRING_SIZE;
            buf_len--;
         }
         if (buf_len > 1)
         {
             snprintf(hex_, hex_len, "\n");
             hex_ += 1;
         }
  } while ((buf_len) > 0 && (hex_len > 0));

}

Ejemplo: código

#define DATA_HEX_STR_LEN 5000
    char      data_hex_str[DATA_HEX_STR_LEN];

    get_hex(pkt, pkt_len, data_hex_str, DATA_HEX_STR_LEN, 16);
    //      ^^^^^^^^^^^^                                  ^^
    //      Input byte array                              Number of (hex) byte
    //      to be converted to hex string                 columns in hex string

    printf("pkt:\n%s",data_hex_str) 

SALIDA

pkt:
BB 31 32 00 00 00 00 00 FF FF FF FF FF FF DE E5 
A8 E2 8E C1 08 06 00 01 08 00 06 04 00 01 DE E5 
A8 E2 8E C1 67 1E 5A 02 00 00 00 00 00 00 67 1E 
5A 01 

0

No hay primitiva para esto en C. Probablemente malloc (o quizás asigne) un búfer lo suficientemente largo y recorra la entrada. También lo he visto hacer con una biblioteca de cadenas dinámica con semántica (¡pero no sintaxis!) Similar a la de C ++ ostringstream, que es una solución plausiblemente más genérica, pero puede que no valga la pena la complejidad adicional solo para un solo caso.


0

Si desea almacenar los valores hexadecimales en una char *cadena, puede usar snprintf. Debe asignar espacio para todos los caracteres impresos, incluidos los ceros y los dos puntos iniciales.

Ampliando la respuesta de Mark:

char str_buf* = malloc(3*X + 1);   // X is the number of bytes to be converted

int i;
for (i = 0; i < x; i++)
{
    if (i > 0) snprintf(str_buf, 1, ":");
    snprintf(str_buf, 2, "%02X", num_buf[i]);  // need 2 characters for a single hex value
}
snprintf(str_buf, 2, "\n\0"); // dont forget the NULL byte

Entonces ahora str_bufcontendrá la cadena hexadecimal.


esto sobrescribe los primeros 2 caracteres una y otra vez ... ¿verdad?
xordon

0

La solución de ZincX adaptada para incluir delimitadores de colon:

char buf[] = {0,1,10,11};
int i, size = sizeof(buf) / sizeof(char);
char *buf_str = (char*) malloc(3 * size), *buf_ptr = buf_str;
if (buf_str) {
  for (i = 0; i < size; i++)
    buf_ptr += sprintf(buf_ptr, i < size - 1 ? "%02X:" : "%02X\0", buf[i]);
  printf("%s\n", buf_str);
  free(buf_str);
}

0

Agregaré la versión C ++ aquí para cualquiera que esté interesado.

#include <iostream>
#include <iomanip>
inline void print_bytes(char const * buffer, std::size_t count, std::size_t bytes_per_line, std::ostream & out) {
    std::ios::fmtflags flags(out.flags()); // Save flags before manipulation.
    out << std::hex << std::setfill('0');
    out.setf(std::ios::uppercase);
    for (std::size_t i = 0; i != count; ++i) {
        auto current_byte_number = static_cast<unsigned int>(static_cast<unsigned char>(buffer[i]));
        out << std::setw(2) << current_byte_number;
        bool is_end_of_line = (bytes_per_line != 0) && ((i + 1 == count) || ((i + 1) % bytes_per_line == 0));
        out << (is_end_of_line ? '\n' : ' ');
    }
    out.flush();
    out.flags(flags); // Restore original flags.
}

Imprimirá el hexdump de la bufferlongitud counta std::ostream out(puede establecerlo por defecto std::cout). Cada línea contendrá bytes_per_linebytes, cada byte se representa usando hexadecimal de dos dígitos en mayúsculas. Habrá un espacio entre bytes. Y al final de la línea o al final del búfer imprimirá una nueva línea. Si bytes_per_linese establece en 0, no imprimirá new_line. Pruébelo usted mismo.


0

Para un uso simple, hice una función que codifica la cadena de entrada (datos binarios):

/* Encodes string to hexadecimal string reprsentation
    Allocates a new memory for supplied lpszOut that needs to be deleted after use
    Fills the supplied lpszOut with hexadecimal representation of the input
    */
void StringToHex(unsigned char *szInput, size_t size_szInput, char **lpszOut)
{
    unsigned char *pin = szInput;
    const char *hex = "0123456789ABCDEF";
    size_t outSize = size_szInput * 2 + 2;
    *lpszOut = new char[outSize];
    char *pout = *lpszOut;
    for (; pin < szInput + size_szInput; pout += 2, pin++)
    {
        pout[0] = hex[(*pin >> 4) & 0xF];
        pout[1] = hex[*pin & 0xF];
    }
    pout[0] = 0;
}

Uso:

unsigned char input[] = "This is a very long string that I want to encode";
char *szHexEncoded = NULL;
StringToHex(input, strlen((const char *)input), &szHexEncoded);

printf(szHexEncoded);

// The allocated memory needs to be deleted after usage
delete[] szHexEncoded;

0

Basado en la respuesta de Yannuth pero simplificado.

Aquí, longitud de dest[] se implica que la es el doble de len, y su asignación es administrada por el llamador.

void create_hex_string_implied(const unsigned char *src, size_t len, unsigned char *dest)
{
    static const unsigned char table[] = "0123456789abcdef";

    for (; len > 0; --len)
    {
        unsigned char c = *src++;
        *dest++ = table[c >> 4];
        *dest++ = table[c & 0x0f];
    }
}

0

Sé que esta pregunta ya tiene una respuesta, pero creo que mi solución podría ayudar a alguien.

Entonces, en mi caso, tenía una matriz de bytes que representaba la clave y necesitaba convertir esta matriz de bytes en una matriz de caracteres de valores hexadecimales para imprimirla en una línea. Extraje mi código a una función como esta:

char const * keyToStr(uint8_t const *key)
{
    uint8_t offset = 0;
    static char keyStr[2 * KEY_SIZE + 1];

    for (size_t i = 0; i < KEY_SIZE; i++)
    {
        offset += sprintf(keyStr + offset, "%02X", key[i]);
    }
    sprintf(keyStr + offset, "%c", '\0');

    return keyStr;
}

Ahora, puedo usar mi función así:

Serial.print("Public key: ");
Serial.println(keyToStr(m_publicKey));

SerialEl objeto es parte de la biblioteca Arduino y m_publicKeyes miembro de mi clase con la siguiente declaración uint8_t m_publicKey[32].


0

Puedes resolverlo con snprintf y malloc.

char c_buff[50];

u8_number_val[] = { 0xbb, 0xcc, 0xdd, 0x0f, 0xef, 0x0f, 0x0e, 0x0d, 0x0c };

char *s_temp = malloc(u8_size * 2 + 1);

for (uint8_t i = 0; i < u8_size; i++)
{
    snprintf(s_temp  + i * 2, 3, "%02x", u8_number_val[i]);
}

snprintf(c_buff, strlen(s_temp)+1, "%s", s_temp );

printf("%s\n",c_buff);

free(s);

FUERA: bbccdd0fef0f0e0d0c


-2

¡Qué soluciones tan complejas!
Malloc y corre y lanza oh mi. (Cita de OZ)
y ni un solo rem en ninguna parte. Dios,

¿qué tal algo como esto?

main()
{
    // the value
    int value = 16;

    // create a string array with a '\0' ending ie. 0,0,0
    char hex[]= {0,0,'\0'}; 
    char *hex_p=hex;

    //a working variable
    int TEMP_int=0;

    // get me how many 16s are in this code
    TEMP_int=value/16;

    // load the first character up with 
    // 48+0 gives you ascii 0, 55+10 gives you ascii A
    if (TEMP_int<10) {*hex_p=48+TEMP_int;}
        else {*hex_p=55+TEMP_int;}

    // move that pointer to the next (less significant byte)<BR>
    hex_p++;

    // get me the remainder after I have divied by 16
    TEMP_int=value%16;

    // 48+0 gives you ascii 0, 55+10 gives you ascii A
    if (TEMP_int<10) {*hex_p=48+TEMP_int;}
        else {*hex_p=55+TEMP_int;}

    // print the result
    printf("%i , 0x%s",value,hex);

}

Bien, ahora tienes dos dígitos hexadecimales. Queda por agregar separadores y cuidar los otros bytes para convertir. ¿Quizás con un bucle? Conviértalo en una función y tendrás algo similar al mío (pero bastante detallado y difícil de leer). ¿Quizás deberías al menos terminar el trabajo antes de poner nombres en otros carteles?
kriss

1
Y una palabra sobre los comentarios en el código fuente (no REM, esa es la palabra clave BÁSICA para los comentarios, por favor evítelo): los comentarios que dicen en inglés lo que hace el código es una muy, muy mala práctica. Sí, se supone que los programadores saben qué significan los operadores de módulo (dar los restos) y esa división cuenta el número de veces que aparece un número en otro ... y que printf imprime el resultado. ¡Oh mi!
kriss
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.