C में एक स्ट्रिंग को पूर्णांक में कैसे बदलें?


260

मैं यह पता लगाने की कोशिश कर रहा हूं कि क्या सी में पूर्णांक में स्ट्रिंग को परिवर्तित करने का एक वैकल्पिक तरीका है।

मैं नियमित रूप से अपने कोड में निम्नलिखित पैटर्न देता हूं।

char s[] = "45";

int num = atoi(s);

तो, क्या कोई बेहतर तरीका है या कोई और तरीका है?


21
आपके टैग और शीर्षक कहते हैं कि आप C में समाधान चाहते हैं, लेकिन आपका प्रश्न C या C ++ कहता है। आप कौन सा चाहते है?
सिल्की

1
@ यन, उस उलझन के लिए खेद है। मैं सी को तरजीह दूंगा।
user618677

1
यह काम करता है, लेकिन यह अनुशंसित तरीका नहीं है, क्योंकि त्रुटियों को संभालने का कोई तरीका नहीं है। जब तक आप इनपुट 100% पर भरोसा नहीं कर सकते उत्पादन कोड में इसका उपयोग न करें।
१47:४er पर उवे ज्यूडर

1
'बेहतर' परिभाषित करें, और स्पष्ट रूप से बताएं कि आपको दूसरे तरीके की आवश्यकता क्यों है
लोर्ने

3
@EJP बस खुद को सुधारना है।
user618677

जवाबों:


185

वहाँ है strtolजो बेहतर है IMO। इसके अलावा, मैंने इसमें एक पसंद किया है strtonum, इसलिए यदि आपके पास इसका उपयोग करें (लेकिन याद रखें कि यह पोर्टेबल नहीं है):

long long
     strtonum(const char *nptr, long long minval, long long maxval,
     const char **errstr);

संपादित करें

आपकी रुचि strtoumaxऔरstrtoimax C99 में मानक कार्य भी हैं। उदाहरण के लिए आप कह सकते हैं:

uintmax_t num = strtoumax(s, NULL, 10);
if (num == UINTMAX_MAX && errno == ERANGE)
    /* Could not convert. */

वैसे भी, इससे दूर रहें atoi:

कॉल atoi (str) के बराबर होगा:

(int) strtol(str, (char **)NULL, 10)

सिवाय इसके कि त्रुटियों की हैंडलिंग अलग हो सकती है। यदि मान का प्रतिनिधित्व नहीं किया जा सकता है, तो व्यवहार अपरिभाषित है


मुझे क्या शामिल करने की आवश्यकता है strtonum? मैं एक अंतर्निहित घोषणा की चेतावनी प्राप्त करता रहता हूं
jsj

@ trideceth12 सिस्टम पर जहाँ यह उपलब्ध है उसे घोषित किया जाना चाहिए #<stdlib.h>। हालाँकि, आप मानक strtoumaxविकल्प का उपयोग कर सकते हैं ।
cnicutar

4
यह उत्तर प्रश्नकर्ता के पहले कोड से कम नहीं लगता है।
Azurespot

11
@NoniA। चिंता हमेशा अच्छी होती है, लेकिन शुद्धता की कीमत पर नहीं।
cnicutar

6
असुरक्षित के रूप में इतना गलत नहीं है। यदि इनपुट वैध है तो atoi () काम करता है। लेकिन अगर आप अटोई ("बिल्ली") करते हैं तो क्या होगा? स्ट्रैटोल () ने व्यवहार को परिभाषित किया है यदि मूल्य को लंबे समय तक नहीं दिखाया जा सकता है, तो अटोई () नहीं करता है।
डेनियल बी।

27

मजबूत C89 strtolआधारित समाधान

साथ में:

  • कोई अपरिभाषित व्यवहार (जैसा कि atoiपरिवार के साथ हो सकता है)
  • पूर्णांक की एक सख्त परिभाषा की तुलना में strtol(उदाहरण के लिए कोई प्रमुख व्हाट्सएप और न ही ट्रैशिंग चर नहीं)
  • त्रुटि मामले का वर्गीकरण (जैसे उपयोगकर्ताओं को उपयोगी त्रुटि संदेश देने के लिए)
  • एक "परीक्षण"
#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;
}

गिटहब ऊपर

इसके आधार पर: https://stackoverflow.com/a/6154614/895245


3
अच्छा मजबूत str2int()। पांडित्य: उपयोग isspace((unsigned char) s[0])
chux -

@chux धन्यवाद! क्या आप थोड़ा और समझा सकते हैं कि (unsigned char)कलाकारों को फर्क क्यों पड़ सकता है?
सिरो सेंटिल्ली 郝海东 冠状 iro 事件 法轮功 '30

IAR C संकलक चेतावनी देता है कि l > INT_MAXऔर l < INT_MINनिरर्थक पूर्णांक तुलना हैं क्योंकि परिणाम हमेशा गलत होता है। अगर मैं उन्हें चेतावनी देने l >= INT_MAXऔर l <= INT_MINचेतावनी देने के लिए बदलूँ तो क्या होगा ? एआरएम सी पर, लंबी और इंट एआरएम सी और सी ++ में
चाचा

l >= INT_MAXगलत कार्यक्षमता को लागू करने के लिए @ecle कोड बदलना : STR2INT_OVERFLOWइनपुट "32767"और 16-बिट के साथ लौटने का उदाहरण int। एक सशर्त संकलन का उपयोग करें। उदाहरण है
chux -

if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) return STR2INT_OVERFLOW;बेहतर होगा if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) { errno = ERANGE; return STR2INT_OVERFLOW;}कि कॉलिंग कोड को आउट-ऑफ-रेंज errnoपर उपयोग करने की अनुमति दी जाए int। उसी के लिए if (l < INT_MIN...
chux -

24

ato...समूह से कार्यों का उपयोग न करें । ये टूट गए हैं और लगभग बेकार हो गए हैं। एक मामूली बेहतर समाधान का उपयोग करना होगा sscanf, हालांकि यह भी सही नहीं है।

स्ट्रिंग को पूर्णांक में बदलने के लिए, strto...समूह से कार्यों का उपयोग किया जाना चाहिए। आपके विशिष्ट मामले में यह strtolकार्य करेगा ।


7
sscanfवास्तव में अपरिभाषित व्यवहार होता है यदि वह अपने प्रकार की सीमा के बाहर की संख्या को बदलने की कोशिश करता है (उदाहरण के लिए, sscanf("999999999999999999999", "%d", &n))।
कीथ थॉम्पसन

1
@ कीथ थॉम्पसन: बिल्कुल यही मेरा मतलब है। atoiकोई सार्थक सफलता / विफलता प्रतिक्रिया प्रदान करता है और अतिप्रवाह पर अपरिभाषित व्यवहार करता है। sscanfप्रकार की सफलता / विफलता प्रतिक्रिया प्रदान करता है (वापसी मूल्य, जो कि इसे "मध्यम रूप से बेहतर" बनाता है), लेकिन अभी भी अतिप्रवाह पर अपरिभाषित व्यवहार है। केवल strtolएक व्यवहार्य समाधान है।
चींटी

1
माना; मैं सिर्फ संभावित घातक समस्या पर जोर देना चाहता था sscanf। (हालांकि मैं कबूल करता हूं कि मैं कभी-कभी उन atoiकार्यक्रमों के लिए उपयोग करता हूं , जिन्हें मैं स्रोत को हटाने से पहले 10 मिनट से अधिक जीवित रहने की उम्मीद नहीं करता हूं।)
कीथ थॉम्पसन

5

आप मज़े के लिए एक छोटे से अटोई () कोड कर सकते हैं:

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);
}

आप इसे पुनरावर्ती भी बना सकते हैं जो 3 पंक्तियों में पुराना हो सकता है =)


बहुत बहुत धन्यवाद .. लेकिन क्या आप मुझे बता सकते हैं कि नीचे दिया गया कोड कैसे काम करता है? code((* str) - '0')code
user618677

एक चरित्र का अस्सी मूल्य है। आप uner linux प्रकार हैं: खोल में आदमी ascii या नहीं तो के लिए जाना table-ascii.com । आप देखेंगे कि चरित्र '0' = 68 (i लगता है) एक इंट के लिए। तो '9' की संख्या प्राप्त करने के लिए (यह '0' + 9) है, इसलिए आपको 9 = '9' - '0' मिलते हैं। आपको यह मिल गया?
jDourlens 16

1
1) कोड "----1" 2 की अनुमति देता है ) intपरिणाम होने पर अतिप्रवाह के साथ अपरिभाषित व्यवहार होता है INT_MIN। विचार करेंmy_getnbr("-2147483648")
chux -

परिशुद्धता के लिए धन्यवाद, यह केवल एक छोटा सा उदाहरण दिखाने के लिए था। जैसा कि यह कहा गया है कि यह मजेदार और सीखने के लिए है। इस तरह के कार्यों के लिए आपको निश्चित रूप से standart lib का उपयोग करना चाहिए। तेज़ और सुरक्षित!
जौर्लेंस

2

सिर्फ अहस्ताक्षरित लंबे समय के लिए एक समाधान साझा करना चाहता था।

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;
}

1
अतिप्रवाह संभाल नहीं करता है। इसके अलावा, पैरामीटर होना चाहिए const char *
रोलैंड इलिग

2
इसके अलावा, 48इसका क्या मतलब है? क्या आप यह मान रहे हैं कि '0'कोड कहां चलेगा? कृपया दुनिया पर इस तरह की व्यापक धारणाओं को न छेड़ें!
टोबी स्पाइट

@TobySpeight हां मैं मानती हूं कि अस्सी टेबल में 48 '0' का प्रतिनिधित्व करते हैं।
जैकब

3
पूरी दुनिया में ASCII नहीं है - '0'जैसे आपको चाहिए वैसे ही इस्तेमाल करें ।
टोबी स्पाइट

इसके बजाय स्ट्रैटोल फ़ंक्शन का उपयोग करने की अनुशंसा की जाती है ।
रैपिडक्लॉक

1
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;
}

-1

आप हमेशा अपना रोल कर सकते हैं!

#include <stdio.h>
#include <string.h>
#include <math.h>

int my_atoi(const char* snum)
{
    int idx, strIdx = 0, accum = 0, numIsNeg = 0;
    const unsigned int NUMLEN = (int)strlen(snum);

    /* Check if negative number and flag it. */
    if(snum[0] == 0x2d)
        numIsNeg = 1;

    for(idx = NUMLEN - 1; idx >= 0; idx--)
    {
        /* Only process numbers from 0 through 9. */
        if(snum[strIdx] >= 0x30 && snum[strIdx] <= 0x39)
            accum += (snum[strIdx] - 0x30) * pow(10, idx);

        strIdx++;
    }

    /* Check flag to see if originally passed -ve number and convert result if so. */
    if(!numIsNeg)
        return accum;
    else
        return accum * -1;
}

int main()
{
    /* Tests... */
    printf("Returned number is: %d\n", my_atoi("34574"));
    printf("Returned number is: %d\n", my_atoi("-23"));

    return 0;
}

यह वही करेगा जो आप अव्यवस्था के बिना चाहते हैं।


2
पर क्यों? यह अतिप्रवाह के लिए जाँच नहीं करता है और केवल कचरा मूल्यों की उपेक्षा करता है। strto...फ़ंक्शंस के परिवार का उपयोग नहीं करने का कोई कारण नहीं है । वे पोर्टेबल और काफी बेहतर हैं।
चाड

1
के 0x2d, 0x30बजाय उपयोग करने के लिए अजीब '-', '0''+'संकेत की अनुमति नहीं देता है । में क्यों (int)डाला (int)strlen(snum)? यूबी यदि इनपुट है ""। UB जब परिणाम के साथ अतिप्रवाह के INT_MINकारण intहोता हैaccum += (snum[strIdx] - 0x30) * pow(10, idx);
chux - Reinstate Monica

@chux - यह कोड प्रदर्शन कोड है। संभावित मुद्दों के रूप में आपके द्वारा बताए गए आसान फ़िक्स हैं।
बट्टडीन

2
@ButchDean जिसे आप "प्रदर्शन कोड" के रूप में वर्णित करते हैं, उसका उपयोग अन्य लोगों द्वारा किया जाएगा जिनके पास सभी विवरणों के बारे में कोई सुराग नहीं है। केवल नकारात्मक स्कोर और इस जवाब पर टिप्पणी अब उनकी रक्षा करते हैं। मेरी राय में, "प्रदर्शन कोड" में बहुत अधिक गुणवत्ता होनी चाहिए।
रोलैंड इलिग

@ रोलैंडलीगेट सभी महत्वपूर्ण होने के बजाय, दूसरों के लिए वास्तव में अपने स्वयं के समाधान के लिए अधिक उपयोगी नहीं होगा?
बुचैन

-1

यह फ़ंक्शन आपकी सहायता करेगा

int strtoint_n(char* str, int n)
{
    int sign = 1;
    int place = 1;
    int ret = 0;

    int i;
    for (i = n-1; i >= 0; i--, place *= 10)
    {
        int c = str[i];
        switch (c)
        {
            case '-':
                if (i == 0) sign = -1;
                else return -1;
                break;
            default:
                if (c >= '0' && c <= '9')   ret += (c - '0') * place;
                else return -1;
        }
    }

    return sign * ret;
}

int strtoint(char* str)
{
    char* temp = str;
    int n = 0;
    while (*temp != '\0')
    {
        n++;
        temp++;
    }
    return strtoint_n(str, n);
}

Ref: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html


1
हालांकि यह क्यों? atoiदोस्तों और दोस्तों के साथ सबसे बड़ी समस्या यह है कि अगर वहाँ अतिप्रवाह है, तो यह अपरिभाषित व्यवहार है। आपका फ़ंक्शन इसके लिए जाँच नहीं करता है। strtolऔर दोस्त करते हैं
चाड

1
हाँ। चूंकि सी पायथन नहीं है, मुझे आशा है कि सी भाषा का उपयोग करने वाले लोग इस तरह की अतिप्रवाह त्रुटियों के बारे में जानते हैं। हर चीज की अपनी सीमा होती है।
अमिथा चिन्तका

-1

ठीक है, मैं एक ही समस्या थी। मैं इस समाधान के साथ आया था। यह मेरे लिए सबसे अच्छा काम किया। मैंने अटोई () की कोशिश की, लेकिन मेरे लिए अच्छा काम नहीं किया। यहाँ मेरा समाधान है:

void splitInput(int arr[], int sizeArr, char num[])
{
    for(int i = 0; i < sizeArr; i++)
        // We are subtracting 48 because the numbers in ASCII starts at 48.
        arr[i] = (int)num[i] - 48;
}

-1
//I think this way we could go :
int my_atoi(const char* snum)
{
 int nInt(0);
 int index(0);
 while(snum[index])
 {
    if(!nInt)
        nInt= ( (int) snum[index]) - 48;
    else
    {
        nInt = (nInt *= 10) + ((int) snum[index] - 48);
    }
    index++;
 }
 return(nInt);
}

int main()
{
    printf("Returned number is: %d\n", my_atoi("676987"));
    return 0;
}

सी। में कोड संकलित नहीं करता है। nInt = (nInt *= 10) + ((int) snum[index] - 48);बनाम क्यों nInt = nInt*10 + snum[index] - '0'; if(!nInt)नहीं आवश्यक है।
chux -

-3

C ++ में, आप ऐसे फ़ंक्शन का उपयोग कर सकते हैं:

template <typename T>
T to(const std::string & s)
{
    std::istringstream stm(s);
    T result;
    stm >> result;

    if(stm.tellg() != s.size())
        throw error;

    return result;
}

यह आपको किसी भी प्रकार को किसी भी प्रकार में बदलने में मदद कर सकता है जैसे कि फ्लोट, इंट, डबल ...


1
C ++ को कवर करने के लिए पहले से ही एक समान प्रश्न है , जहां इस दृष्टिकोण के साथ समस्याओं को समझाया गया है।
बेन वोइगट

-6

हां, आप पूर्णांक को सीधे स्टोर कर सकते हैं:

int num = 45;

यदि आपको एक स्ट्रिंग पार्स करनी है, atoiया strol"कम से कम मात्रा में कोड" प्रतियोगिता जीतने जा रही है।


यदि आप इसे सुरक्षित रूप से करना चाहते हैं, तो strtol()वास्तव में उचित मात्रा में कोड की आवश्यकता होती है। यह LONG_MINया LONG_MAX तो वापस आ सकता है या यदि यह वास्तविक रूपांतरित मान है या यदि कोई अंडरफ्लो या अतिप्रवाह है, और यह 0 वापस आ सकता है यदि वह वास्तविक मूल्य है या यदि कोई संख्या नहीं है तो उसे परिवर्तित करें। आपको errno = 0कॉल करने से पहले सेट करना होगा , और चेक करना होगा endptr
कीथ थॉम्पसन

पार्स करने के लिए दिए गए समाधान, कोई व्यवहार्य समाधान नहीं हैं।
BananaAcid
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.