c - ¿Cómo convertir un número entero en una cadena (función)?

CorePress2024-01-16  11

Necesito ayuda con este código, si alguien tuviera un problema similar, me ayudaría.

Es necesario modificar el siguiente código, para que al ingresar valores enteros en la función formulario, imprima ese valor entero como una cadena.

Por ejemplo:

s = form(3,123, 456, 789);

Necesitan imprimir: 123456789.

Este es el código:

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

char* form(int n,...)
{
    char *result = 0, *next;
    int i;
    va_list args;
    va_start(args, n);
    for (i = 0; i < n; i++) {
        int len = result ? strlen(result) : 0;
        next = va_arg(args, char *);
        char *tmp = (char *)malloc(len + strlen(next) + 1);

        strcpy(tmp, result ? result : "");
        strcat(tmp, next);
        free(result);
        result = tmp;
    }
    va_end(args);
    return result;
}

int main(void)
{
    char *s;
    s = form(3,123, 456, 789);
    printf("%s", s);
    free(s);
    return 0;
}

¡Gracias de antemano! ¡Saludos cordiales!

2

Utilice sprintf() para convertir un número entero en una cadena.

-Barmar

19/03/2021 a las 18:32

Los argumentos de la función son int, ¿por qué estás usando char *next?

-Barmar

19/03/2021 a las 18:33

Así consta en el código en el que se debe realizar la modificación correspondiente.

Seguro para PC

19/03/2021 a las 18:34

Usar char* en lugar de int* no convierte el número entero en una cadena, solo da como resultado un comportamiento indefinido cuando se trata como una cadena.

- interjay

19/03/2021 a las 18:43

¿Cuál es la motivación para usar vargs?

- Ed Heal

19/03/2021 a las 18:47



------------------------------------

Si todo lo que necesitas es imprimir y no almacenar, es mucho más sencillo hacerlo directamente en stdout sin ninguna asignación. Esto está bien documentado en c faq.

#include <stdio.h>
#include <stdarg.h>

void form(unsigned n, ...) {
    va_list argp;
    va_start(argp, n);
    while(n) n--, printf("%d", va_arg(argp, int));
    va_end(argp);
    printf("\n");
}

int main(void) {
    form(3, 123, 456, 789);
    return 0;
}

Si tiene la intención de almacenar y asignar mal el resultado, puede que le resulte más fácil contar los caracteres necesarios en un bucle alrededor de va_arg con snprintf usando 0 como n, asignarlos y luego completarlos en otro bucle.



------------------------------------

Esto servirá:

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

char* form(int n, ...)
{
    char *result = malloc(n * 11 + 1); // int is at most 11 characters long.
    char *position = result;

    va_list args;
    va_start(args, n);

    for (int i = 0; i < n; i++)
    {
        int next = va_arg(args, int);
        sprintf(position, "%i", next);
        position += strlen(position);
    }

    va_end(args);
    return result;
}

int main()
{
    char *s = form(3, 123, 456, 789);
    printf("%s", s);
    free(s);
    return 0;
}

0



------------------------------------

Problemas obvios:

Su entrada prevista es "int", pero los trataste como "char*"
    next = va_arg(args, char *);
    char *tmp = (char *)malloc(len + strlen(next) + 1);
Su primera entrada debe tratarse como una extensión de "longitud".

Vea mi solución rápida.

Descargo de responsabilidad: solo he probado unos pocos casos.

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

int decimal_len(int in) {
  int max_len_dec_int = 1000000000;
  int len = 10;
  while (len > 1) {
    if (in >= max_len_dec_int) {
      break;
    }
    max_len_dec_int /= 10;
    len--;
  }
  return len;
}

char *form(int n, ...) {
  char *result = 0;
  int next;
  int i;
  va_list args;
  va_start(args, n);

  if (n < 2) {
    printf("invalid parameter\n");
    exit(-1);
  }

  for (i = 0; i < n; i++) {
    int len = result ? strlen(result) : 0;
    next = va_arg(args, int);
    char *new_str = (char *)malloc(decimal_len(next) + 1);
    sprintf(new_str, "%d", next);
    char *tmp = (char *)malloc(len + decimal_len(next) + 1);
    strcpy(tmp, result ? result : "");
    strcat(tmp, new_str);
    result = tmp;
  }
  va_end(args);
  return result;
}

int main() {
  {
    char *s;
    s = form(3, 123, 456, 789);
    printf("%s", s);
    free(s);
  }
  printf("\nAnother test\n");
  {
    char *s;
    s = form(4, 123, 456, 789, 123);
    printf("%s", s);
    free(s);
  }
  return 0;
}

3

1

decimal_len está intentando hacer el trabajo de sprintf(new_str, "%d", next); para predeterminar la longitud. Podría usar string_length = snprintf(0, 0, "%d", next); para encontrar la longitud y estar seguro de que tiene la misma longitud que en el siguiente sprintf(new_str, "%d", next);.

– chux - Reincorporar a Mónica

19/03/2021 a las 20:45

1

@chux-ReinstateMonica Sí, ambos obtienen el mismo resultado y un rendimiento similar. La solución snprintf es mucho más sencilla.

-Zongru Zhan

21/03/2021 a las 15:14

@chux-ReinstateMonica Por cierto, hice una prueba comparativa simple y descubrí que mi solución simple es mucho más rápida que la anterior.nprintf uno (~30X). Aunque supongo que rara vez valdría la pena optimizarlo en la práctica.

-Zongru Zhan

23/03/2021 a las 17:19



------------------------------------

Mi solución:

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

#define SZ 32
char* form(int n,...)
{
  char *result = calloc(1,1);
  va_list args;
  va_start(args, n);
  while(n --> 0)
  {
    int number = va_arg(args, int);
    char txt[SZ] = {0};
    char* c = txt+SZ-2;
    for(;number; --c,  number /= 10)
    {
        *c = number%10 + '0';
    }
    c++;
    result = strcat(realloc(result, strlen(result)+strlen(c)+1), c);
  }
  va_end(args);
  return result; // Caller MUST free
}


int main()
{
  char *s = form(3,123, 456, 7890);
  printf("%s", s);
  free(s);
  return 0;
}

Esto es ineficiente porque llama repetidamente tanto a realloc como a strlen. También puede resultar difícil de seguir porque llena un búfer al revés. Pero creo que funciona.



------------------------------------

va_arg(args, char *); tiene más sentido como va_arg(args, int); siLos argumentos son int.

Simplificación:

Asigne una vez a las necesidades del peor de los casos.

Convierta cada int en una cadena con sprintf(). Evite todas las llamadas innecesarias a strlen(), strcat(), strcpy() utilizando el valor de retorno de sprintf() para realizar un seguimiento de dónde imprimir. Evite un algoritmo lento.

Ajuste el tamaño del buffer con los derechos.

Asegúrate de liberar() cuando hayas terminado.

Código de muestra

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

// With 32-bit int, INT_MIN uses 11 characters.
#define INT_STR_LEN ((size_t)11)

char* form(unsigned n, ...) {
  // Determine worst case need.
  size_t sz = n * INT_STR_LEN + 1;
  char *s = malloc(sz);
  if (s) {
    char *end = s;  // Keep track of the end of the string.
    *end = '1008611';    // In case n == 0
    va_list args;
    va_start(args, n);
    // Convert each argument to a string
    for (unsigned i = 0; i < n; i++) {
      int len = sprintf(end, "%d", va_arg(args, int)); // Print at the end
      if (len >= 0) {
        end += len; // Update length
      }
    }
    va_end(args);
    // Right size allocation
    sz = (size_t) (end - s) + 1;
    void *t = realloc(s, sz);
    if (t) {
      s = t;
    }
  }
  return s;
}

int main() {
  char *s;
  s = form(3, 123, 456, 789);
  printf("%s\n", s);
  free(s);
  return 0;
}

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare