-1

I am trying to convert a string of numerical characters to their corresponding integral form. Please suggest what is wrong with the code. I would like to stick with pointers. I understand that the pointer str points to the first character in my string. So, each time I call my function in the loop, I want the pointer to increment by 1, and add the value of the character to one node in my array. For some reason, though I am unable to do so. Here is the code.

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>

int ctoi(char *c);

int main (void)
{
    char *str;
    int A[20];
    int i = 0;
    str = (char*) malloc(20 * sizeof(char));
    printf("Input the string. ");
    scanf("%s", str);
    while(str != '\0')   
    {
        A[i] = ctoi(str);
        i++;
        str++;
    }
    for(i = 0; i < strlen(str); i++)
        printf("%d", A[i]);

    getchar();
    getchar();
    return 0;
}

int ctoi(char *c)
{
    int a;
    a= *c - '0';
    return a;
}
Zereges
  • 5,139
  • 1
  • 25
  • 49
Lexicon
  • 145
  • 1
  • 7

7 Answers7

5

for (i=0;i<strlen(str);i++) printf("%d", A[i]);

Here strlen will return 0 because you updated str in your previous loop .Replace it with :

for(i=0;i<len;i++) 

where len is the length of your input string .Find it before using str in while loop

while(str!='\0') should be `while(*str!='\0')`

. You will get it . But for writing your own atoi function you dont need to store the number in an array

Vijay P R
  • 1,162
  • 1
  • 10
  • 16
1

Please try this it works, the myatoi() function was lifted perhaps 20 years ago from the classic "THE C PROGRAMMING LANGUAGE" , get the book.

#include <stdio.h>

main()
{
    char temp[99];

    strcpy(temp , "34");

    printf( "\n %d " , myatoi(temp));
    strcpy( temp , "8642");
    printf( "\n %d " , myatoi(temp));
}


int myatoi( char s[])
{
    int i,n,sign;
    // skip white space
    for( i=0 ; s[i]==' ' || s[i]=='\n' ||s[i]=='\t';i++) ;

    sign=1;
    if( s[i]=='+' || s[i]=='-')
        sign=( s[i++]=='+' ? 1 : -1 );

    for( n=0; s[i]>='0' && s[i]<='9' ; i++)
        n=10*n+s[i]-'0' ;

    return(sign*n);
}
BobRun
  • 756
  • 5
  • 12
  • When `int myatoi()` should result in `INT_MIN`, `n=10*n+s[i]-'0'` overflows which is undefined behavior. – chux - Reinstate Monica Oct 30 '15 at 14:36
  • That book is old, if main(){} was used, should be at least int main(void){} and you should declare **myatoi**. Any why do he need a book from **20 years ago**? – Michi Oct 30 '15 at 17:49
1

OP's code needs a few (at least 2) fixes to mostly work. See ***

int main (void)
{
    char *str;
    int A[20];
    int i = 0;

    // ***  Cast not needed, '* sizeof(char)' not needed
    str = malloc(20);

    printf("Input the string. ");
    scanf("%s", str);

    // ***
    char *str_original = str;
    while(*str != '\0')


    {
        A[i] = ctoi(str);
        i++;
        str++;
    }

    // ***
    str = str_original;

    for(i = 0; i < strlen(str); i++)
        printf("%d", A[i]);

    // ***
    free(str);  // Good to return memory
    str = NULL;

    getchar();
    getchar();
    return 0;
}

A simple way to convert a string to an int

int strtoi(const char *s) {
  int sum = 0;
  char ch;
  char sign = *s;
  if (*s == '-' || *s == '+') s++;
  while ((ch = *s++) >= '0' && ch <= '9') {
    sum = sum * 10 - (ch - '0');
  }
  if (sign != '-') {
    sum = -sum;
  }
  return sum;
}

Notes: This code accumulates the sum on the negative side of 0 to avoid UB when trying to parse the string for INT_MIN. Modified code could skip leading white-space, add text error detection, overflow detection, etc.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • **int i** should be **size_t i**. Any way good example. and you forgot to check scanf for errors. – Michi Oct 30 '15 at 17:57
  • @Michi Agree OP's code would benefit with numerous changes, hence the "mostly work" in the answer. Amongst these are `size_t i` and check `scanf()` as you commented. Also, overflow, sign characters, no need for an allocated array, repeated calls of `strlen(str)`, etc. But this is not a [code review](http://codereview.stackexchange.com) site, so focusing on the some of the more important ones. BTW: suggest trying that site to bring coding to the next level. – chux - Reinstate Monica Oct 30 '15 at 18:16
  • Good point, my intention was only for OP and nothing more because it's very important to stick with the language. – Michi Oct 30 '15 at 18:20
1

Here is my custom atoi funtion, who handle unsigned int with debug gestion:

int     my_getnbr(char *str)
{
  int   nb;
  int   sign;
  int   i;

  nb = 0;
  sign = 0;
  i = -1;
  if (!str)
    return (0);
  while (str[++i])
    if (str[i] < '0' && str[i] > '9' && str[i] != '-' && str[i] != '+')
      return (0);
  i = 0;
  while (str[i] != '\0' && (str[i] == '-' || str[i] == '+'))
    if (str[i++] == '-')
      ++sign;
  while (str[i] && (str[i] >= '0' && str[i] <= '9'))
    {
      nb = (nb * 10) + (str[i++] - '0');
      if (str[i] == ' ')
        i++;
    }
  return (((sign % 2) == 1) ? ((nb) * (-1)) : (nb));
}

tested with that main:

int main()
{
  printf("%d\n", my_getnbr("-42"));
  printf("%d\n", my_getnbr("-+-+--42"));
  printf("%d\n", my_getnbr("-0"));
  printf("%d\n", my_getnbr("590310"));
  return (0);
}

No leaks, here is the result:

-42
42
0
590310
Ugo Hed
  • 185
  • 1
  • 11
0

Firstly

while(str!='\0') should be

while(*str!='\0')

You should compare the content, not the address.

And while printing the returned data, you are doing

for(i=0;i<strlen(str);i++)
   printf("%d", A[i]);

str already parsed till the last. So length would probably be 0.

Change your while loop to

 while(*str!='\0')   
      {   
        A[i]=ctoi(*str);
        i++;
        str++;
      } 

And your function to

int ctoi(char c)
 {
 int a;
 a= c-'0'; 
 return a;
 }
Raghu Srikanth Reddy
  • 2,703
  • 33
  • 29
  • 42
0

There are several approaches for a simple atoi replacement without the base conversion flexibility in strtol. The simplest is generally to find the length of the string to convert, and then work backward toward the front of the string preforming the conversion from string to integer as you go. A quick example would be:

/* a quick atoi replacement */
int atoi2 (char *s)
{
    int nmax = (1ULL << 31) - 1;    /* INT_MAX  */
    long long n = 0;    /* the number to return */
    size_t m = 1;       /* multiplier for place */
    size_t l = 0;       /* length of string     */

    char *p = s;
    while (*p++) l++;   /* get string length        */
    p -= 2;             /* position at last char    */

    while (l--)         /* for each char in string  */
    {   /* verify a digit or '-' sign */
        if ((*p >= '0' && *p <= '9') || *p == '-')
        {
            if (*p == '-') { /* if '-' is first char */
                if (p == s) n = -n;  /* negate value */
            }
            else {  /* otherwise normal conversion   */
                n += (*p - '0') * m;
                if (n > nmax) { /* prevent overflow  */
                    fprintf (stderr, "atoi2() error: conversion > INT_MAX.\n");
                    exit (EXIT_FAILURE);
                }
                m *= 10;
            }
        }
        p--;
    }
    return (int) n;
}

A simple driver program to test could be:

#include <stdio.h>
#include <stdlib.h>

int atoi2 (char *s);

int main (int argc, char **argv) {

    if (argc < 1) return 1;

    printf ("\n string : %s, conversion : %d\n\n",
            argv[1], atoi2 (argv[1]));

    return 0;
}

Example Use/Output

$ ./bin/atoi2 321

 string : 321, conversion : 321

$ ./bin/atoi2 -321

 string : -321, conversion : -321


$ ./bin/atoi2 2147483647

 string : 2147483647, conversion : 2147483647

$ ./bin/atoi2 2147483648
atoi2() error: conversion > INT_MAX.

If you have any questions, please do not hesitate to ask.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

Here is a custom atoi function that avoids using most of the standard library functions

/*** _atoi - finds the first set of integers in a given string
 * @s: string entered
* Return: first number sequence
**/

int _atoi(char *s)
{
    int length = 0, negativeCount = 0, count = 0, num = 0;

    while (s[length] != '\0')
    {
        length++;
    }
    while (count < length)
    {
        if (s[count] == '-')
        {
            negativeCount++;
        }
        if (s[count] >= 48 && s[count] <= 57)
        {
            /* ascii values for numbers */
            for (; s[count] >= 48 && s[count] <= 57; count++)
            {
                num = (10 * num - (s[count] - 48));
            }
            break;
        }
        count++;
    }
    if (negativeCount % 2 != 0)
    {
        return (num);
    }
    else
    {
        return (-num);
    }
}
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38