Ich versuche herauszufinden, ob es eine alternative Möglichkeit gibt, Strings in C in Integer umzuwandeln.
Ich mustere regelmäßig Folgendes in meinem Code.
char s[] = "45";
int num = atoi(s);
Gibt es also einen besseren oder einen anderen Weg?
Benutzer618677
Ich versuche herauszufinden, ob es eine alternative Möglichkeit gibt, Strings in C in Integer umzuwandeln.
Ich mustere regelmäßig Folgendes in meinem Code.
char s[] = "45";
int num = atoi(s);
Gibt es also einen besseren oder einen anderen Weg?
Cnicutar
Es gibt strtol
das ist besser IMO. Auch ich habe Gefallen gefunden strtonum
verwenden Sie es also, wenn Sie es haben (aber denken Sie daran, dass es nicht portabel ist):
long long
strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
Das könnte Sie auch interessieren strtoumax
und strtoimax
die Standardfunktionen in C99 sind. Du könntest zum Beispiel sagen:
uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
/* Could not convert. */
Bleiben Sie jedenfalls fern atoi
:
Der Aufruf atoi(str) ist äquivalent zu:
(int) strtol(str, (char **)NULL, 10)
außer dass die Behandlung von Fehlern abweichen kann. Wenn der Wert nicht dargestellt werden kann, ist das Verhalten undefiniert.
wofür muss ich eintragen strtonum
? Ich bekomme immer eine implizite Deklarationswarnung
– jsj
30. März 2013 um 1:57 Uhr
@ trideceth12 Auf Systemen, auf denen es verfügbar ist, sollte es deklariert werden #<stdlib.h>
. Sie können jedoch den Standard verwenden strtoumax
Alternative.
– Cnicutar
30. März 2013 um 10:21 Uhr
Diese Antwort scheint nicht kürzer zu sein als der erste Code des Fragestellers.
– Azurespot
3. September 2014 um 4:46 Uhr
@NoniA. Prägnanz ist immer gut, aber nicht auf Kosten der Korrektheit.
– Cnicutar
3. September 2014 um 9:33 Uhr
Nicht so sehr falsch als unsicher. atoi() funktioniert, wenn die Eingabe gültig ist. Aber was ist, wenn Sie atoi (“Katze”) tun? strtol() hat ein definiertes Verhalten, wenn der Wert nicht als long dargestellt werden kann, atoi() nicht.
– Daniel B.
22. Juli 2015 um 19:13 Uhr
Ciro Santilli OurBigBook.com
Robuster C89 strtol
-basierte Lösung
Mit:
atoi
Familie)strtol
(z. B. kein führendes Leerzeichen oder nachgestellte Papierkorbzeichen)#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
typedef enum {
STR2INT_SUCCESS,
STR2INT_OVERFLOW,
STR2INT_UNDERFLOW,
STR2INT_INCONVERTIBLE
} str2int_errno;
/* Convert string s to int out.
*
* @param[out] out The converted int. Cannot be NULL.
*
* @param[in] s Input string to be converted.
*
* The format is the same as strtol,
* except that the following are inconvertible:
*
* - empty string
* - leading whitespace
* - any trailing characters that are not part of the number
*
* Cannot be NULL.
*
* @param[in] base Base to interpret string in. Same range as strtol (2 to 36).
*
* @return Indicates if the operation succeeded, or why it failed.
*/
str2int_errno str2int(int *out, char *s, int base) {
char *end;
if (s[0] == '\0' || isspace(s[0]))
return STR2INT_INCONVERTIBLE;
errno = 0;
long l = strtol(s, &end, base);
/* Both checks are needed because INT_MAX == LONG_MAX is possible. */
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
return STR2INT_OVERFLOW;
if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
return STR2INT_UNDERFLOW;
if (*end != '\0')
return STR2INT_INCONVERTIBLE;
*out = l;
return STR2INT_SUCCESS;
}
int main(void) {
int i;
/* Lazy to calculate this size properly. */
char s[256];
/* Simple case. */
assert(str2int(&i, "11", 10) == STR2INT_SUCCESS);
assert(i == 11);
/* Negative number . */
assert(str2int(&i, "-11", 10) == STR2INT_SUCCESS);
assert(i == -11);
/* Different base. */
assert(str2int(&i, "11", 16) == STR2INT_SUCCESS);
assert(i == 17);
/* 0 */
assert(str2int(&i, "0", 10) == STR2INT_SUCCESS);
assert(i == 0);
/* INT_MAX. */
sprintf(s, "%d", INT_MAX);
assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
assert(i == INT_MAX);
/* INT_MIN. */
sprintf(s, "%d", INT_MIN);
assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
assert(i == INT_MIN);
/* Leading and trailing space. */
assert(str2int(&i, " 1", 10) == STR2INT_INCONVERTIBLE);
assert(str2int(&i, "1 ", 10) == STR2INT_INCONVERTIBLE);
/* Trash characters. */
assert(str2int(&i, "a10", 10) == STR2INT_INCONVERTIBLE);
assert(str2int(&i, "10a", 10) == STR2INT_INCONVERTIBLE);
/* int overflow.
*
* `if` needed to avoid undefined behaviour
* on `INT_MAX + 1` if INT_MAX == LONG_MAX.
*/
if (INT_MAX < LONG_MAX) {
sprintf(s, "%ld", (long int)INT_MAX + 1L);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
}
/* int underflow */
if (LONG_MIN < INT_MIN) {
sprintf(s, "%ld", (long int)INT_MIN - 1L);
assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
}
/* long overflow */
sprintf(s, "%ld0", LONG_MAX);
assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
/* long underflow */
sprintf(s, "%ld0", LONG_MIN);
assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
return EXIT_SUCCESS;
}
Basierend auf: https://stackoverflow.com/a/6154614/895245
Schön robust str2int()
. Pedant: verwenden isspace((unsigned char) s[0])
.
– chux – Wiedereinsetzung von Monica
30. Mai 2016 um 12:09 Uhr
@chux danke! Können Sie etwas näher erklären, warum die (unsigned char)
Besetzung könnte einen Unterschied machen?
– Ciro Santilli OurBigBook.com
30. Mai 2016 um 13:00 Uhr
Der IAR C-Compiler warnt davor l > INT_MAX
und l < INT_MIN
sind sinnlose Integer-Vergleiche, da beide Ergebnisse immer falsch sind. Was passiert, wenn ich sie zu ändere? l >= INT_MAX
und l <= INT_MIN
um die Warnungen zu löschen? Auf ARM C, lang und int sind 32-Bit-signiert Grundlegende Datentypen in ARM C und C++
– Ecle
26. Januar 2017 um 2:23 Uhr
@ecle Code ändern in l >= INT_MAX
führt zu fehlerhafter Funktionalität: Beispielrückgabe STR2INT_OVERFLOW
mit Eingang "32767"
und 16bit int
. Verwenden Sie eine bedingte Kompilierung. Beispiel.
– chux – Wiedereinsetzung von Monica
20. Dezember 2017 um 12:45 Uhr
if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;
wäre besser als if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}
um die Verwendung des aufrufenden Codes zu ermöglichen errno
an int
außer Reichweite. Das gleiche für if (l < INT_MIN...
.
– chux – Wiedereinsetzung von Monica
22. September 2018 um 17:44 Uhr
AnT steht zu Russland
Verwenden Sie keine Funktionen von ato...
Gruppe. Diese sind kaputt und praktisch unbrauchbar. Eine mäßig bessere Lösung wäre zu verwenden sscanf
obwohl es auch nicht perfekt ist.
Um String in Integer umzuwandeln, funktioniert from strto...
Gruppe verwendet werden soll. In Ihrem speziellen Fall wäre es strtol
Funktion.
sscanf
hat tatsächlich ein undefiniertes Verhalten, wenn es versucht, eine Zahl außerhalb des Bereichs seines Typs zu konvertieren (z. B. sscanf("999999999999999999999", "%d", &n)
).
– Keith Thompson
11. August 2011 um 6:50 Uhr
@Keith Thompson: Genau das meine ich. atoi
liefert kein sinnvolles Erfolgs-/Fehler-Feedback und hat ein undefiniertes Verhalten bei Überlauf. sscanf
bietet eine Art Erfolgs-/Fehlerrückmeldung (der Rückgabewert, der es “mäßig besser” macht), hat aber immer noch ein undefiniertes Verhalten beim Überlauf. Nur strtol
ist eine gangbare Lösung.
– AnT steht zu Russland
11. August 2011 um 6:55 Uhr
Einverstanden; Ich wollte nur das potenziell fatale Problem mit betonen sscanf
. (Obwohl ich gestehe, dass ich manchmal benutze atoi
normalerweise für Programme, von denen ich nicht erwarte, dass sie länger als 10 Minuten überleben, bevor ich die Quelle lösche.)
– Keith Thompson
11. August 2011 um 6:58 Uhr
GrandMarquis
Du kannst codieren atoi()
zum Spass:
int my_getnbr(char *str)
{
int result;
int puiss;
result = 0;
puiss = 1;
while (('-' == (*str)) || ((*str) == '+'))
{
if (*str == '-')
puiss = puiss * -1;
str++;
}
while ((*str >= '0') && (*str <= '9'))
{
result = (result * 10) + ((*str) - '0');
str++;
}
return (result * puiss);
}
Sie können es auch rekursiv machen, was in 3 Zeilen gefaltet werden kann.
Biswajit Karmakar
int atoi(const char* str){
int num = 0;
int i = 0;
bool isNegetive = false;
if(str[i] == '-'){
isNegetive = true;
i++;
}
while (str[i] && (str[i] >= '0' && str[i] <= '9')){
num = num * 10 + (str[i] - '0');
i++;
}
if(isNegetive) num = -1 * num;
return num;
}
Jacob
Ich wollte nur eine Lösung für unsigned long teilen.
unsigned long ToUInt(char* str)
{
unsigned long mult = 1;
unsigned long re = 0;
int len = strlen(str);
for(int i = len -1 ; i >= 0 ; i--)
{
re = re + ((int)str[i] -48)*mult;
mult = mult*10;
}
return re;
}
Lundin
Wie bereits erwähnt, die atoi
Funktionsfamilie sollten niemals in einem C-Programm verwendet werden, da sie keine Fehlerbehandlung haben.
Die … Die strtol
Die Funktionsfamilie ist zu 100 % gleichwertig, jedoch mit erweiterter Funktionalität: Sie verfügt über eine Fehlerbehandlung und unterstützt auch andere Basen als Dezimalzahlen, wie z. B. Hex oder Binär. Daher lautet die richtige Antwort: verwenden strtol
(Familie).
Wenn Sie aus irgendeinem Grund darauf bestehen, diese Funktion selbst manuell auszurollen, sollten Sie versuchen, etwas Ähnliches zu tun strtol
falls andere Symbole als das optionale Zeichen und die Ziffern vorhanden sind. Es ist durchaus üblich, dass wir beispielsweise Zahlen konvertieren möchten, die Teil einer größeren Zeichenfolge sind.
Eine naive Version mit Fehlerbehandlungsunterstützung könnte wie im folgenden Beispiel aussehen. Dieser Code ist nur für Dezimalzahlen auf Basis 10, verhält sich aber ansonsten wie strtol
mit einem optionalen Zeigersatz, der auf das erste gefundene ungültige Symbol zeigt (falls vorhanden). Beachten Sie auch, dass dieser Code keine Überläufe behandelt.
#include <ctype.h>
long my_strtol (char* restrict src, char** endptr)
{
long result=0;
long sign=1;
if(endptr != NULL)
{
/* if input is ok and endptr is provided,
it will point at the beginning of the string */
*endptr = src;
}
if(*src=='-')
{
sign = -1;
src++;
}
for(; *src!='\0'; src++)
{
if(!isdigit(*src)) // error handling
{
if(endptr != NULL)
{
*endptr = src;
}
break;
}
result = result*10 + *src - '0';
}
return result * sign;
}
Um Überläufe zu handhaben, kann man beispielsweise Code hinzufügen, der die Zeichen zählt und überprüft, dass sie nie über 10 hinausgehen, vorausgesetzt, 32 Bit long
das kann max 2147483647
10 Ziffern.
(Ich komme sehr spät zur Party, aber hier wird so viel schlechter Code gepostet. Wenn Sie dies manuell ausrollen, machen Sie zumindest nichts schlechter als atoi
.)
– Ludin
13. Dezember 2021 um 14:44 Uhr
@ Yann, Entschuldigung für diese Verwirrung. Ich bevorzuge C.
– Benutzer618677
11. August 2011 um 16:16 Uhr
programmierungsimplified.com/c/source-code/…
– Kyle Bridenstine
28. September 2014 um 1:07 Uhr
Es funktioniert, aber es ist nicht der empfohlene Weg, da es keine Möglichkeit gibt, Fehler zu behandeln. Verwenden Sie dies niemals im Produktionscode, es sei denn, Sie können der Eingabe zu 100 % vertrauen.
– Uwe Geuder
5. November 2015 um 17:47 Uhr
@EJP Nur um mich zu verbessern.
– Benutzer618677
3. August 2018 um 1:32 Uhr