sintaxis - scanf %d
Cómo obtener enteros y flotantes de entrada sin `scanf()` en c? (3)
¿Cómo puedo asignar valores enteros y flotantes dados por el usuario a una variable o matriz sin usar scanf()
?
Al igual que tenemos getchar
, fgetc
, fgets
... etc para char
y string
, ¿hay alguna función para flotantes y enteros?
¿Hay alguna función para flotantes y enteros?
Sí, es scanf()
, pero OP no quiere usar eso.
¿Cómo obtener la entrada de entero y flotante sin
scanf()
?
Esta no es una tarea trivial que hacer simplemente como scanf("%d", &some_int)
, scanf("%f", &some_float)
.
El principal problema es dejar de leer los caracteres una vez que se haya consumido la entrada válida más larga, esto podría estar en el medio de una línea de entrada del usuario. No encontré una solución robusta.
En cambio, consideró el problema de leer una línea de entrada del usuario por un entero de long
. Leer un float
es similar. Cambios necesarios cerca de las líneas ***
Todavía se produce el problema de la longitud de texto finito. El código siguiente supone que la entrada válida está compuesta por hasta el doble del máximo necesario para imprimir una long
.
El desbordamiento es un problema abordado aquí. Recordar con scanf()
, OF / UF es un comportamiento indefinido.
La idea central es leer una línea omitiendo espacios en blanco, leyendo N caracteres y luego buscando cualquier espacio no blanco después de eso. Luego analiza el buffer.
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// character array size needed to represent all `long`
#define INT_STR_SIZE (sizeof(long)*CHAR_BIT/3 + 3)
#define INT_BUF_SIZE (INT_STR_SIZE*2)
int readline_long(long *dest) { // ***
int ch;
while (isspace(ch = getchar()) && ch != ''/n'') {
;
}
if (ch == EOF) return EOF;
ungetc(ch, stdin);
char buf[INT_BUF_SIZE]; // ***
if (fgets(buf, sizeof buf, stdin) == NULL) return EOF;
if (strchr(buf, ''/n'') == NULL) {
// Get rest of line
bool only_white_space = true;
while ((ch = getchar()) != ''/n'' && ch != EOF) {
if (!isspace(ch)) only_white_space = false; // consume rest of line
}
if (!only_white_space) return 0; // extra junk
}
char *endptr;
errno = 0;
long y = strtol(buf, &endptr, 10); // ***
if (buf == endptr) return false; // no conversion
while (isspace((unsigned char) *endptr)) {
endptr++;
}
if (*endptr) return 0; // extra junk
*dest = y;
return 1;
}
Código de prueba
int main(void) {
long lg;
int retval;
while ((retval = readline_long(&lg)) != EOF) {
printf("retval = %d", retval);
if (retval > 0) printf(" val = %ld", lg);
if (errno) printf(" errno = %d", errno);
putchar(''/n'');
fflush(stdout);
}
}
Hace años escribí esto, Probado en VS2017 y todavía funciona. Muy simple, no muy bueno, pero tal vez puedas usarlo para algo
#define INT_CONVERTED (1 << 0)
#define FLOAT_CONVERTED (1 << 1)
char *strlwr(char *str)
{
char *ptr = str;
while (*ptr)
{
*ptr = tolower(*ptr);
ptr++;
}
return str;
}
int NumberOfDots(char *s)
{
int dots = 0;
while (*s)
dots += *s++ == ''.'';
return dots;
}
int NOTstrcasechr(char *str, int ch)
{
return strchr(str, ch) == NULL && strchr(str, toupper(ch)) == NULL;
}
int ReadNumber(double *db, int *in)
{
int result = 0;
do
{
char str[100];
int dots;
result = 0;
printf("Enter number: ");
fgets(str, 100, stdin);
if ((dots = NumberOfDots(str)) > 1) str[0] = ''/0'';
if (sscanf(str, "%lf", db) == 1)
{
result |= FLOAT_CONVERTED;
}
if (!result || (!dots && NOTstrcasechr(str, ''e'')))
if (NOTstrcasechr(str, ''x''))
{
if (sscanf(str, "%d", in) == 1)
{
result |= INT_CONVERTED;
}
}
else
if(result)
{
result |= INT_CONVERTED;
*in = (int)*db;
}
if (strstr(strlwr(str), "exit") != NULL) result = -1;
} while (!result);
return result;
}
int main(int argc, char **argv)
{
double db;
int in;
int result;
while ((result = ReadNumber(&db, &in)) != -1)
{
if (result & FLOAT_CONVERTED) printf("Float = %lf ", db);
if (result & INT_CONVERTED) printf("Integer = %d ", in);
printf("/n/r");
}
return 0;
}
Enter number: xfdsfdsfdsf
Enter number: rthdgfhghg
Enter number: 0x4567
Float = 17767.000000 Integer = 17767
Enter number: 3e67
Float = 30000000000000000978680950144401383192292617328216608963406365458432.000000
Enter number: 54567
Float = 54567.000000 Integer = 54567
Enter number: dfgdfgdfgdfgdgg
Enter number: 3456
Float = 3456.000000 Integer = 3456
Enter number: 12354654465454654654565567567576
Float = 12354654465454653961713368432640.000000 Integer = -1
Enter number: exit
No hay funciones para leer números enteros y flotantes, pero puede usar fgets
con strtol
para enteros y strtof
para flotantes:
// floats:
char str_f[20];
float f;
fgets (str_f, 20, stdin);
f = strtof(str_f, NULL);
// integers:
char str_i[20];
int i;
fgets(str_i, 20, stdin);
i = strtol(str_i, NULL, 0);
También puede usar atoi
para enteros, pero no se recomienda porque atoi
no detecta errores y se considera obsoleto.
Si desea detectar errores, puede usar el siguiente código:
// floats:
char *endptr_f;
char str_f[20];
float f;
fgets (str_f, 20, stdin);
f = strtof(str_f, &endptr_f);
if (*endptr_f != ''/n'' || str_f[0] == ''/n'' || endptr_f == str_f)
{
printf("ERROR: /"%s/" is an invalid float!/n", str_f);
}
// integers:
char *endptr_i;
char str_i[20];
int i;
fgets(str_i, 20, stdin);
i = strtol(str_i, &endptr_i, 0);
if (*endptr_i != ''/n'' || str_i[0] == ''/n'' || endptr_i == str_i)
{
printf("ERROR: /"%s/" is an invalid integer!/n", str_i);
}