itoa () C implementation in min underflow
je fais quelques essais avec ma fonction itoa () mais je continue à avoir
did not allocate memory for the int min value
je fais l'addition mais c'est quelque chose que je manque ici, qu'est-ce que c'est?
char *ft_itoa(int x) {
char *s;
size_t len;
long int n;
n = x;
if (x == -2147483648)
return (ft_strdup("-2147483648"));
len = ft_intlen(n) + 1;
if (!(s = (char*)malloc(sizeof(char) * len)))
return (NULL);
if (n == 0)
s[0] = '0';
if (n < 0) {
s[0] = '-';
n = -n;
}
s[len - 1] = '';
while (n) {
len--;
s[len - 1] = (n % 10) + '0';
n /= 10;
}
return (s);
}
7 réponses
Cette ligne:
if (x == -2147483648)
ne fait pas ce que vous pensez qu'il fait. C n'a pas de constantes entières négatives. Il s'agit d'une constante int non signée avec la valeur 2^31, sur laquelle vous appliquez l'opérateur unary minus. Cela signifie que l'expression x == -21...
dépendra de la norme C votre compilateur utilise.
si vous utilisez C99 ou C11, tout ira bien. Il y a un type signé qui est assez grand - long long est garanti d'être assez grand pour ce nombre, donc à la fois x et -21... sera être converti en long, puis de les comparer. Mais si vous utilisez un compilateur C89 et que votre machine n'a pas un type assez long, vous rencontrez ici un comportement défini par l'implémentation:
Lorsqu'un entier est rétrogradé à un entier signé de plus petite taille, ou qu'un entier non signé est converti en son entier signé correspondant, si la valeur ne peut pas être représentée, le résultat est défini par implémentation.
C'est pourquoi les gens disent à utiliser limite.H. Non pas parce qu'ils sont pédants, mais parce que c'est un territoire dangereux. Si vous regardez attentivement quelles limites.h contient, vous aurez plus de chances de trouver une ligne comme ceci:
#define INT_MIN (- INT_MAX - 1)
cette expression a en fait le type et la valeur corrects.
a part ça, Je ne vois aucune erreur dans le code que vous avez posté. Si ce n'est pas le problème ft_intlen
ou ft_strdup
sont mauvais. Ou vous appelez votre fonction dans testing incorrect (les mêmes problèmes s'appliquent à -21... lorsque l'appel de tests).
statut: résolu invalide
raison: WORKS_FOR_ME
de toute façon, je me suis amélioré sur certains points.
sizeof(char)
est toujours de 1, pas besoin.- ne pas cast
malloc
- si vous traitez le cas spécial 0, alors traitez-le en une seule fois.
-2147483648
est très très mauvais. C'est ce queINT_MIN
.- retour n'est pas une fonction, n'est pas de retour
(value)
, il suffit de revenirvalue
. - ne pas
s[len - 1]
tous les temps, mieux décrémentelen
avant d'entrer dans la boucle. Ou, puisque vous avez besoin d'len + 1
dans lemalloc
appel, il suffit d'avoirlen
intlen
renvoie et appellemalloc
en utilisantlen + 1
ft_itoa.c
#include <stdbool.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <btstr.h>
int ft_intlen(int n) {
char buffer[8192];
return snprintf(buffer, sizeof buffer, "%i", n);
}
char * ft_itoa(int n) {
char * s;
size_t l, len;
bool fix_int_min = false;
if (!n) {
return mstrcpy("0");
}
if (-INT_MAX != INT_MIN && n == INT_MIN) {
++n;
fix_int_min = true;
}
len = ft_intlen(n);
if (!(s = malloc(len + 1))) {
return NULL;
}
if (n < 0) {
s[0] = '-';
n = -n;
}
s[l = len] = '';
while (n) {
s[--len] = (n % 10) + '0';
n /= 10;
}
if (fix_int_min) {
--l;
while (s[l] == '9') {
s[l++] = 0;
}
if (s[l] == '-') {
// realloc +1 and write "-1[0....0]"
} else {
++s[l];
}
}
return s;
}
main.c
#include <limits.h>
#include <stdio.h>
char * ft_itoa(int n);
void check(int n) {
printf("%i = %s\n", n, ft_itoa(n));
}
int main() {
check(0);
check(-1);
check(1);
check(23);
check(42);
check(4711);
check(1000);
check(INT_MAX);
check(1+INT_MIN);
check(INT_MIN);
}
Résultat
$ gcc -W -Wall -Wextra -lBtLinuxLibrary ft_itoa.c main.c -o ft_itoa && ./ft_itoa
0 = 0
-1 = -1
1 = 1
23 = 23
42 = 42
4711 = 4711
1000 = 1000
2147483647 = 2147483647
-2147483647 = -2147483647
-2147483648 = -2147483648
Vous n'avez pas besoin de vérifier. Convertissez-le plutôt en unsigned
, qui correspondra à la valeur absolue :
size_t ft_uintlen(unsigned n)
{
size_t len = 0;
do {
++len;
n /= 10;
} while(n);
return len;
}
char *ft_itoa(int x)
{
char *s;
size_t len;
unsigned n;
int negative;
negative = x < 0;
n = negative ? 0-(unsigned)x : (unsigned)x;
len = ft_uintlen(n) + negative + 1;
if (!(s = (char*)malloc(len)))
return (NULL);
s[--len] = '';
if (negative)
s[0] = '-';
do {
s[--len] = (n % 10) + '0';
n /= 10;
} while(n);
return (s);
}
notez que ceci utilise un nouveau size_t ft_uintlen(unsigned)
fonction qui fonctionne sur unsigned
arguments.
Probablement problème dans votre dépassement de mécanisme de prévention. Vous essayez d'attribuer x
de type int
n
avec le type long int
. Mais la spécification ne garantit pas ce type long int
peut gérer la gamme de valeur de grandes alors int
. Plus d'informations peuvent être trouvées " Long Vs. Int"!--17-->.
Utiliser long long int
tapez n
si votre compilateur le supporte. Mise à jour de votre ft_intlen
function int ft_intlen(long long int n)
. Dans ce cas, vous serez en mesure de gérer l'ensemble du int
valeur de type gamme et supprimer les lignes suivantes:
if (x == -2147483648)
return (ft_strdup("-2147483648"));
aussi message d'erreur did not allocate memory for the int min value
n'est pas l'un de l' numéros d'erreur du système. Vous devez ajouter plus de journalisation dans votre application, surtout s'il n'est pas possible de la Déboguer pour une raison quelconque. Vérifier errno
pour chaque appel de fonction système, par exemple:
char* errmsg;
// Other code skipped here
if (!(s = (char*)malloc(sizeof(char) * len)))
{
errmsg = strerror(errno); // Use strerror_s if possible
printf("Malloc error: %s\n", errmsg);
return (NULL);
}
Echec de codes potentiels, par ordre de suspicion:
ft_strdup()
que ce code est appelé avec "int valeur min" et l'erreur se produit.- Prototypes manquant pour diverses fonctions. Surtout
ft_strdup()/strdup()
. - le code D'appel/d'essai est défectueux.
- "int valeur min" est plus grand que -2147483648. (Il est mieux d'utiliser
INT_MIN
.) ft_intlen(n)
est mal codé et retourneINT_MAX
, puis le code essaiemalloc(INT_MIN)
.int/long
les deux 64 bits. Cela crée le premiers[len - 1] = (n % 10) + '0';
INT_MIN
.
Sinon, si INT_MIN
a la valeur de -2147483648, ft_itoa(int x)
c'est bien.
OP asserts"... strdup attribue juste la chaîne, ft_intlen renvoie juste la longueur de la chaîne, les deux passent les cas de test – franklinexpress Oct 8 à 7: 52"
la réussite des cas de test ne signifie pas qu'il a fonctionné sans invoquer un comportement non défini. Le meilleur de la poste ft_intlen()
,ft_strdup()
et le harnais d'essai pour examen.
Candidat portable mise en oeuvre. Pas de dépendance à <limits.h> mis à part CHAR_BIT
quel code supposons que 8 est sans sacrifier trop de potentialité. Fonctionne avec C89 / 99 / 11.
// Buffer size needed to decimal print any `int`
// '-' + Ceiling(value bit size * log10(2)) +
#define INT_STR_SIZE (1 + ((CHAR_BIT*sizeof(int) - 1)/3 + 1) + 1)
char *ft_itoa(int x) {
char buf[INT_STR_SIZE];
char *s = buf + sizeof buf - 1; // Set to end of buffer
*s = '';
int n = x; // no need for wider types like long
if (n > 0) {
// fold positive numbers to negative ones
// This avoids the special code for `INT_MIN` and need for wider types
n = -n;
}
// Using a do loop avoids special code for `x==0`
do {
// Use `div()` rather than / % in case we are using C89.
// / % has implementation defined results for negative arguments.
div_t qr = div(n, 10);
*--s = (char) ('0' - qr.rem); // Form digit from negative .rem
n = qr.quot;
} while (n);
if (x < 0) {
*--s = '-';
}
// Double check ft_strdup() is coded correctly
// Insure calling code frees the buffer when done.
return ft_strdup(s);
}
le morceau de code que vous avez donné compile et fonctionne sur OsX, mais avec mon propre ft_stdup
et ft_intlen
. Ainsi, vous pouvez nous montrer le code ou les vérifier pour les erreurs.
J'ai fait quelques tests (dont 2147483647, -2147483648). Il fonctionne très bien.
de toute façon, les lignes suivantes:
if (x == -2147483648)
return (ft_strdup("-2147483648"));
Sont inutiles tant que vous copiez votre x
valeur long long
variable ( Art) avant toute opération. Si vous n'avez pas besoin, y compris types.h
(la célèbre moulinette ne vous donnera pas -42).
il arrive que sur OsX il fonctionne aussi sur long
valeurs, mais c'est un coffre-fort non portable.
utilisation:
INT_MIN
au lieu de:
-2147483648
dans votre test:
if (x == INT_MIN)
return (ft_strdup("-2147483648"));
la raison en est que certains compilateurs pourraient avoir de la difficulté à comprendre ce nombre.
La bibliothèque standard C limites.h habituellement, définissez - le comme suit:
#define INT_MIN (-INT_MAX - 1)
pour éviter ce problème.