কিভাবে একটি স্ট্রিং সি তে পূর্ণসংখ্যায় রূপান্তর করবেন?


260

আমি সিটিতে স্ট্রিংকে পূর্ণসংখ্যায় রূপান্তর করার বিকল্প উপায় আছে কিনা তা অনুসন্ধান করার চেষ্টা করছি

আমি নিয়মিতভাবে আমার কোডটিতে নীচে প্যাটার্ন করি।

char s[] = "45";

int num = atoi(s);

তাহলে, এর চেয়ে ভাল উপায় বা অন্য কোনও উপায় আছে?


21
আপনার ট্যাগ এবং শিরোনাম বলছে যে আপনি সি তে একটি সমাধান চান তবে আপনার প্রশ্নটি সি বা সি ++ বলে। তুমি কোনটি চাও?
সিলিকো

1
@ ইয়ান, এই বিভ্রান্তির জন্য দুঃখিত। আমি সি পছন্দ করব।
ব্যবহারকারী 618677

1
এটি কাজ করে, তবে এটি প্রস্তাবিত উপায় নয়, কারণ ত্রুটিগুলি পরিচালনা করার কোনও উপায় নেই is আপনি যদি 100% ইনপুটকে বিশ্বাস না করতে পারেন তবে উত্পাদন কোডে এটিকে কখনই ব্যবহার করবেন না।
উওয়ে গিউডার 17

1
'আরও ভাল' সংজ্ঞায়িত করুন এবং আপনার অন্য উপায় কেন প্রয়োজন তা স্পষ্টভাবে উল্লেখ করুন ।
লার্নের মারকুইস

3
@ এজেপি কেবল নিজেকে উন্নত করতে।
ব্যবহারকারী 618677

উত্তর:


185

এখানে strtolআরও ভাল আইএমও রয়েছে। এছাড়াও আমি পছন্দ করে নিয়েছি 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 (স্ট্র) এর সমান হবে:

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

ত্রুটিগুলি পরিচালনা করা পৃথক হতে পারে except মানটি উপস্থাপন করা না গেলে, আচরণটি সংজ্ঞায়িত


আমি কি জন্য অন্তর্ভুক্ত করা প্রয়োজন strtonum? আমি একটি অন্তর্নিহিত ঘোষণার সতর্কতা পেয়ে
যাচ্ছি

@ trideceth12 এটি যে সিস্টেমে উপলব্ধ সেগুলিতে এটি ঘোষণা করা উচিত #<stdlib.h>। তবে আপনি স্ট্যান্ডার্ড strtoumaxবিকল্পটি ব্যবহার করতে পারেন ।
cnicutar

4
এই উত্তরটি প্রশ্নকারীর প্রথম কোডের চেয়ে কম মনে হচ্ছে না।
আজুরস্পট

11
@NoniA। সংক্ষিপ্ততা সর্বদা ভাল, তবে নির্ভুলতার ব্যয়ে নয়।
cnicutar

6
অনিরাপদ হিসাবে এত ভুল নয়। atoi () ইনপুটটি বৈধ হলে কাজ করে। তবে আপনি যদি আটাই ("বিড়াল") করেন তবে কী হবে? স্ট্র্টল () মানটিকে দীর্ঘ হিসাবে উপস্থাপন করতে না পারলে আচরণকে সংজ্ঞায়িত করে, আটাই () না করে।
ড্যানিয়েল বি।

27

দৃ Rob় সি 89 strtolভিত্তিক সমাধান

সঙ্গে:

  • কোনও অপরিবর্তিত আচরণ ( atoiপরিবারের সাথে যেমন করা যেতে পারে )
  • চেয়ে পূর্ণসংখ্যা একটি কঠোর সংজ্ঞা strtol(যেমন কোন নেতৃস্থানীয় হোয়াইটস্পেস কিংবা trailing ট্র্যাশ অক্ষর)
  • ত্রুটি মামলার শ্রেণিবদ্ধকরণ (উদাহরণস্বরূপ ব্যবহারকারীদের কার্যকর ত্রুটির বার্তা দেওয়ার জন্য)
  • একটি "টেস্টুয়েট"
#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
দুর্দান্ত দৃust় str2int()। পেডেন্টিক: ব্যবহার isspace((unsigned char) s[0])
chux - মনিকা পুনরায় ইনস্টল করুন

@ chux ধন্যবাদ! আপনি কি আরও কিছু ব্যাখ্যা করতে পারেন কেন (unsigned char)কাস্ট একটি পার্থক্য করতে পারে?
সিরো সান্তিলি 郝海东 冠状 病 六四 事件

আইএআর সি সংকলক হুঁশিয়ারি উচ্চারণ করে l > INT_MAXএবং l < INT_MINঅর্থহীন পূর্ণসংখ্যার তুলনা হয় যেহেতু উভয় ফলাফল সর্বদা মিথ্যা। আমি যদি তাদের এ পরিবর্তন করি l >= INT_MAXএবং l <= INT_MINসতর্কতাগুলি সাফ করি তবে কী হবে ? এআরএম সি তারিখে, দীর্ঘ এবং int- এ 32-বিট সাইন করে এআরএম সি এবং C ++ বেসিক ধরনের তথ্য
ecle

@ l >= INT_MAXকার্যকারিতাটি ভুল কার্যকারিতাকে অন্তর্ভুক্ত করে: 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((* code
টিআর

একটি চরিত্রের একটি আসকি মান রয়েছে। আপনি যদি আনার লিনাক্স টাইপ হন: শেলটিতে লোকটি আস্কি বা না গেলে: টেবিল- এসসিআই.কম । আপনি দেখতে পাবেন যে কোনও অক্ষরের জন্য '0' = 68 (আমি মনে করি) অক্ষরটি। সুতরাং '9' এর নম্বর পেতে (এটি '0' + 9) যাতে আপনি 9 = '9' - '0' পান। আপনি এটি পেতে?
jDourlens

1
1) "----1" কোডটির অনুমতি দেয় 2) intফলাফলটি কখন হওয়া উচিত ওভারফ্লোর সাথে অপরিবর্তিত আচরণ INT_MIN। বিবেচনা করুনmy_getnbr("-2147483648")
chux - মনিকা পুনরায় ইনস্টল

নির্ভুলতার জন্য ধন্যবাদ, এটি কেবলমাত্র একটি সামান্য উদাহরণ দেখানোর জন্য। যেমন এটি মজাদার এবং শেখার জন্য বলা হয়েছে। এই ধরণের কাজের জন্য আপনার অবশ্যই স্ট্যান্ডার্ড লিব ব্যবহার করা উচিত। আরও দ্রুত এবং নিরাপদ!
jDourlens

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'কোডটি কোথায় চলবে তার মান ? দয়া করে বিশ্বকে এমন বিস্তৃত অনুমান দান করবেন না!
টবি স্পিড

@ টবিস্পাইট হ্যাঁ আমি ধরে নিয়েছি 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)Castোকা কেন (int)strlen(snum)? ইনপুট হলে ইউবি"" । ইউবি যখন ফলাফলINT_MINintaccum += (snum[strIdx] - 0x30) * pow(10, idx);
চাক্সের

@ chux - এই কোডটি প্রদর্শনের কোড। আপনি সম্ভাব্য সমস্যা হিসাবে বর্ণনা করেছেন তাতে সহজ সমাধান রয়েছে।
বুচডিয়ান

2
@ বাচডিয়ান আপনি "প্রদর্শন কোড" হিসাবে যা বর্ণনা করেন তা অন্যরা ব্যবহার করবেন যাঁদের সমস্ত বিবরণ সম্পর্কে কোনও ধারণা নেই। কেবলমাত্র নেতিবাচক স্কোর এবং এই উত্তরের মন্তব্যগুলি এখন তাদের রক্ষা করে। আমার মতে, "প্রদর্শনের কোড" এর অবশ্যই অনেক বেশি মানের হতে হবে।
রোল্যান্ড ইলিগ

@ রোল্যান্ডইলিগ সমস্ত সমালোচনা করার পরিবর্তে, অন্যদের পক্ষে আসলে নিজের সমাধান সমাধান করা আরও কার্যকর হবে না?
বুচডিয়ান

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

রেফ: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html


1
কেন এই কেন? atoiএবং বন্ধুদের সাথে সবচেয়ে বড় সমস্যা হ'ল যদি ওভারফ্লো হয় তবে এটি অনির্ধারিত আচরণ। আপনার ফাংশন এটি পরীক্ষা করে না। strtolএবং বন্ধুরা করতে।
চাদ

1
হা. যেহেতু সি পাইথন নয়, আমি আশা করি যে লোকেরা সি ভাষা ব্যবহার করে তারা এই ধরণের ওভারফ্লো ত্রুটি সম্পর্কে সচেতন। সব কিছুর নিজস্ব সীমা থাকে।
অমিত চিন্থাকা

-1

ঠিক আছে, আমারও একই সমস্যা ছিল I আমি এই সমাধানটি নিয়ে এসেছি t এটি আমার পক্ষে সবচেয়ে ভাল কাজ করেছে at

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

সি ++ এ আপনি এই জাতীয় ফাংশন ব্যবহার করতে পারেন:

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
ইতিমধ্যে সি ++ কে কভার করার অনুরূপ একটি প্রশ্ন রয়েছে , যেখানে এই পদ্ধতির সমস্যাগুলি ব্যাখ্যা করা হয়েছে।
বেন ভয়েগ্ট

-6

হ্যাঁ, আপনি সরাসরি পূর্ণসংখ্যা সঞ্চয় করতে পারেন:

int num = 45;

যদি আপনাকে অবশ্যই একটি স্ট্রিং বিশ্লেষণ করতে পারে, atoiবা strol"সংক্ষিপ্ত পরিমাণের কোড" প্রতিযোগিতা জিততে চলেছে।


আপনি যদি এটি নিরাপদে করতে চান তবে strtol()আসলে একটি মোটামুটি কোড দরকার। এটা তোলে আসতে পারেন LONG_MINবা LONG_MAX পারেন যে যদি প্রকৃত রূপান্তরিত মান অথবা একটি underflow বা ওভারফ্লো, এবং এটা হয় 0 আসতে পারেন যে যদি প্রকৃত মূল্য বা যদি রূপান্তর করতে কোন সংখ্যা ছিল পারেন। আপনাকে errno = 0কল করার আগে সেট করতে হবে এবং চেক করতে হবে endptr
কিথ থমসন

পার্সে প্রদত্ত সমাধানগুলি কোনও কার্যকর সমাধান নয়।
কলাআসিড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.