-1
#include <assert.h>
#include <stddef.h>
#include <string.h>

int StringToInteger(const char *str) {
    int num = 0;
    int sign = 1;
    assert(str != NULL); //assert that str different from NULL
    if (*str == '+' || *str == '-') {
        sign = (*str == '-') ? -1 : 1;
        str++;
        return sign; // if sign start with character
    }
    
    while (*str != '\0') { 
        if (*str >= '0' && *str <= '9') {
            num = num * 10 + (*str - '0');
        } else {
            return 0;
        }
        str++;
    }
    return 0;
}

I tried to write a different version of the code without using the regular conversion functions but with no success.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Does [this](https://stackoverflow.com/questions/34767434/convert-string-to-integer-without-library-function-in-c) solve your question? – Parker Feb 13 '23 at 16:55
  • And what problem are you running into, exactly? You haven't stated in your question. – B Remmelzwaal Feb 13 '23 at 16:55
  • 4
    Where do you return `num`? You're always returning 0 or `sign`. – tkausl Feb 13 '23 at 16:55
  • You're also returning out of the function the second you reach a positive or negative sign. What are you expecting to happen? – B Remmelzwaal Feb 13 '23 at 16:56
  • Technically it's impossible to write any C program without functions, as the mandatory `main` function is a function. Or do you mean without using any kind of standard function that might convert a string to a number? Please [edit] your question to copy-paste the full and complete assignment (copy-paste as *text*). – Some programmer dude Feb 13 '23 at 16:57
  • @Someprogrammerdude The text of the question says "without using the regular convert functions". The title is just a brief summary, as it's supposed to be. – Barmar Feb 13 '23 at 17:04
  • 1
    Remove `return sign` and change the last `return 0` to `return num` – Barmar Feb 13 '23 at 17:05
  • Off-topie: When you use code like `assert(str != NULL);` for error-checking, all of your error checking will disappear if someone compiles the code the `-DNDEBUG`, which is pretty common for release builds. Nevermind that aborting the entire process is usually somewhat of an overreaction to bad input. – Andrew Henle Feb 13 '23 at 17:13
  • The standard conversion functions all skip leading white space, and stop converting (without error) at the first character that can't be part of the number. The functions in the `strtol()` family report where they stopped converting and also prevent numeric overflows. You have no mechanism to report failure. You also reject strings with any characters not relevant to the number. That's a legitimate design decision, though not necessarily the best choice. I'd usually allow leading and trailing white space, but there are times when more stringent rules are desirable. – Jonathan Leffler Feb 13 '23 at 19:34

3 Answers3

2

Problems:

Do not always return 0 @tkausl

No reason to return after finding a sign @Barmar

Delete that line and later in code adjust num per sign.
Tip: also run spell checker.

      // return sign; // if sign start with charcter

    // End of code
    return num * sign; // Include this line
    // return 0;

Advanced: avoid int overflow

  • Handle the INT_MIN text like StringToInteger("-2147483648")

  • Detect potential overflow before it happens. This prevents undefined behavior (UB).

#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>

int StringToInteger(const char* str) {
  assert(str != NULL);

  // TBD code if desired to ignore leading white-spaces. 

  int sign = *str;
  if (*str == '+' || *str == '-') {
    str++;
  }

  const char *first = s;
  int num = 0;
  while (*str >= '0' && *str <= '9') { 
    int digit = *str - '0';
    if (num <= INT_MIN/10 && (num < INT_MIN/10 || digit > -(INT_MIN%10))) {
      errno = ERANGE;
      num = INT_MIN;
    } else {
      // Sum as a negative value as the - range is more than + range.
      num = num * 10 - digit;
    }
    str++;
  }
  if (*str) {
    ; // May want to set errno.
    return 0; // Non-null character stopped loop.
  }
  if (s == first) {
    ; // May want to set errno.
    return 0; // No digits.
  }

  if (sign != '-') {
    if (num < -INT_MAX) {
      num = INT_MAX;
      errno = ERANGE;
    } else {
      num = -num;
    }
  }

  return num;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

The function has many return statements that do not make sense as for example

return sign; // if sign start with charcter

And your function returns either sign or 0. In fact it does not take into account the sign of the stored value in the string.

Also take into account that the string can contain leading or trailing white space characters.

You could implement the function the same way.as standard C function strtol. A simplified function can ignore the case when the stored number is too big to fit in an object of the type int.

Here is a demonstration program that shows how the function can be implemented.

#include <ctype.h>
#include <stdio.h>

int StringToInteger( const char *str )
{
    const int Base = 10;

    int sign = 0;

    while (isspace( ( unsigned char )*str )) ++str;

    if (*str == '-' || *str == '+')
    {
        if (*str == '-') sign = 1;
        ++str;
    }

    int value = 0;

    for (unsigned char c = *str;  isdigit( c ); c = *++str )
    {
        int digit = c - '0';
        value = Base * value + ( sign ? -digit : digit );
    }

    while (isspace( ( unsigned char )*str )) ++str;

    return *str == '\0' ? value : 0;
}

int main( void )
{
    const char *str = " -12345\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " 12345\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " 12345\tA";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " @12345\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );

    str = " 123@45\t";

    printf( "\"%s\" = %d\n", str, StringToInteger( str ) );
}

The program output is

" -12345        " = -12345
" 12345 " = 12345
" 12345 A" = 0
" @12345        " = 0
" 123@45        " = 0
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Function converting string to integer (any base if you have enough digits/letters/symbols) to represent digits in this base.

int myisspace(int c)
{
    switch(c)
    {
        case ' ':
        case '\t':
        case '\r':
        case '\n':
        return 1;
    }
    return 0;
}

char *mystrchr(const char *str, const char ch)
{
    while(*str)
    {
        if(*str == ch) return str;
        str++;
    }
    return NULL;
}

int long long cnv(const char *str, unsigned base)
{
    const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int sign = 1;
    int long long result = 0;

    if(str && (base >=2 && base < sizeof(digits)))
    {
        while(myisspace(*str)) str++;
        if(*str == '-' || *str == '+') { sign = *str == '-' ? -1 : 1; str++;}
    }
    while(*str)
    {
        //you may check for overflow as well
        //TODO integer overflow code if needed
        char *rch = mystrchr(digits, *str);
        if(!rch || (rch - digits) >= base)
        {
            if(!myisspace(*str))
            {
                result = 0;
                break;
            }
            else
            {
                *str++;
                continue;
            }
        }
        result *= base;
        result += rch - digits;
        str++;
    }
    return result * sign;
}

int main(void)
{
    printf("%lld\n", cnv("934", 10));
    printf("%lld\n", cnv("934", 12));
    printf("%lld\n", cnv("ffff", 16));
    printf("%lld\n", cnv("01100110011", 2));
    printf("%lld\n", cnv("      -01100110011", 2));
    printf("%lld\n", cnv("      -42313442323", 5));
    printf("%lld\n", cnv("      -42313442323      ", 12));
}
0___________
  • 60,014
  • 4
  • 34
  • 74