Thread: How efficient do you think is this Int To String Converter Function?

  1. #1
    Registered User
    Join Date
    Dec 2017
    Posts
    22

    How efficient do you think is this Int To String Converter Function?

    Hello! I'm new to this forum!

    I'm creating a Dynamic C String Library and i'm not glad about a function i created (About Efficient), because it does so many allocations and deallocations based on the length of the number ( number of digits).

    This function takes as input an integer and returns the corresponding string.

    Code:
    //Create A CString From A Number.
    CString_String *CString_FromInt(int number)
    {
        
        //Calculate the length of the number ( #digits ).
        int length = floor(log10(abs(number))) + 1;
    
    
        //Just an int variable.
        int digit;
    
    
        //Is the number negative?
        int isNegative = number < 0;
    
    
        CString_String *final_string = CString_CreateEmpty();;
        CString_String *digit_string;
        CString_String *temp_string;
        
        //Make sure the number is positive.
        number = abs(number);
    
    
        //Cut the digits from the number.
        for (int i = 0; i < length; i++) 
        {
            //Next digit.
            digit = number % 10;
    
    
            //Convert the digit into a CString.
            digit_string = CString_FromChar( (char)(digit + '0') );
    
    
            //Keep a reference to the final string.
            temp_string  = final_string;
    
    
            //Join the digit with to the final string.
            final_string = CString_Join(digit_string, final_string);
    
    
            //Destroy unnecessary memory.
            CString_Destroy(digit_string);
            CString_Destroy(temp_string);
    
    
            //Divide the number.
            number /= 10;
        }
    
    
        //Add the minus character to the string.
        if (isNegative)
        {   
            //Keep a reference to the final string.
            temp_string = final_string;
    
    
            //Create the minus CString.
            digit_string = CString_FromChar('-');
    
    
            //Join it with the final string.
            final_string = CString_Join(digit_string, final_string);
    
    
            //Destroy unnecessary memory.
            CString_Destroy(digit_string);
            CString_Destroy(temp_string);
        }
    
    
        //Return the CString Successfully.
        return final_string;
    }
    I did the math and this is the amount of mallocs and frees i'm doing in this algorithm:

    Code:
    n: the number of digits
    
    
    mallocs = 2 + 4*n + 4 = 6 + 4*n
    frees   = 4*n + 4
    
    
    For Example:
    
    
    if number = 1234567890
    
    
    n = 10
    
    
    mallocs = 6 + 4*10 = 46
    frees   = 4*10 + 4 = 44
    I guess that's not good.

    What if i'm making a game and every frame i need to convert an int to a string using this function? If we say that the game runs at 60fps
    i will have to do all this mallocs and frees 60 times per second!!! I think this will not be very efficient.

    What do you think?
    Last edited by babaliaris; 12-23-2017 at 06:36 PM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    I think you should just use sprintf.

    Your code is also broken when you try to convert the largest negative integer.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jun 2017
    Posts
    157
    Personally I don't like that the caller has to remember to delete the returned string.
    A better interface IMO would be:
    Code:
    int CString_FromInt(int number, char *output, int size)
    which you could call like this.
    Code:
     char buffer[16] = {0};
    int res = CString_FromInt(1234, buffer, sizeof(buffer)); 
    if (res == 1)
        /*handle error*/
    res should be 0 for error, != 0 for success

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by OldGuy2 View Post
    Personally I don't like that the caller has to remember to delete the returned string.
    A better interface IMO would be:
    Code:
    int CString_FromInt(int number, char *output, int size)
    which you could call like this.
    Code:
     char buffer[16] = {0};
    int res = CString_FromInt(1234, buffer, sizeof(buffer)); 
    if (res == 1)
        /*handle error*/
    res should be 0 for error, != 0 for success
    I don't like that either, but i wanted to avoid arrays and sizes, i wanted to be more Java like :P not that i'm a java person, but this way is easier for the eye.
    Now about an error, you are right, i can't return an error since i'm returning the pointer.

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by Salem View Post
    I think you should just use sprintf.

    Your code is also broken when you try to convert the largest negative integer.
    Yes you are right. There is not absolute value of INT_MIN since a signed int can't represent it. Math.h documentation says that abs(INT_MIN) result is undefined and u can't expect what you will get, but has anyone solved this problem?

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by Salem View Post
    I think you should just use sprintf.

    Your code is also broken when you try to convert the largest negative integer.
    You are more that right, I should use sprintf.

    Code:
    #include <string.h>
    
    
    int main()
    {
        float num = 12.34;
        char s[6];
    
    
        sprintf(s, "%.2f", num);
    
    
        printf("%s", s);
        return 0;
    }
    I just want one advice. When i define the dst array, the size must include the null character? For example here 12.34 will be 5 chars + the null char total size is 6.

    Also for strcat and strcpy is the same?:

    Code:
    #include "../Headers/CString.h"
    #include <string.h>
    
    
    int main()
    {
        char *s1 = "Hello ";
        char *s2 = "World!!!";
    
    
        char s[strlen(s1) + strlen(s2) + 1];
    
    
        strcpy(s, s1);
        strcat(s, s2);
    
    
        printf("%s, %d", s, strlen(s));
        return 0;
    }
    Am i using the buffers correctly? I just wanna be sure not to end up to some buffer overflows.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    An integer with a finite number of bits has a finite upper bound on the number of bytes you need for it's decimal representation. Why don't you malloc that much just once at the start.

    You can realloc to the actual size at the end, but IMO I wouldn't bother. Modern malloc implementations have minimum sizes like 8 or 16 bytes. You can ask for 2 bytes, but the chunk of memory it occupies will be larger.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by Salem View Post
    An integer with a finite number of bits has a finite upper bound on the number of bytes you need for it's decimal representation. Why don't you malloc that much just once at the start.

    You can realloc to the actual size at the end, but IMO I wouldn't bother. Modern malloc implementations have minimum sizes like 8 or 16 bytes. You can ask for 2 bytes, but the chunk of memory it occupies will be larger.
    Yes, I should probably not bother. Anyway i was making this Library because i'm making a game in C and i need to play with strings. I guess strcpy, strcat, strlen, strcmp, sprintf, atoi, atof, will be enough to do my job and also they will do it fast!!! But i'll probably need to create my own algorithms about replacing characters into a string or string slicing operations like the ones you can do in python

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    So i followed Salem's advice, and i created these function wrappers:

    Code:
    //Return's 1 for success, 0 otherwise.
    int CString_ToInt(int *dst, char *string){
    
    
        *dst = atoi(string);
    
    
        return 1;
    }
    
    
    //Return's 1 for success, 0 otherwise.
    int CString_ToFloat(float *dst, char *string){
    
    
        *dst = atof(string);
    
    
        return 1;
    }
    
    
    //Return's 1 for success, 0 otherwise.
    int CString_ToDouble(double *dst, char *string){
    
    
        *dst = (double)atof(string);
    
    
        return 1;
    }
    How can i check if the input string is correct? I noticed that atoi() and atof() returns 0 if the string is not a string that represents a number but this is not enough. If i use the string "0" or the string "abs" i will get the same result 0 two times, the first one will be correct but the second means "abs" can't be converted to an integer.

    So what can i do for that?

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    You should be using strtol(), strtoul() and strtod() for your conversions.
    They return better success/fail information.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by Salem View Post
    You should be using strtol(), strtoul() and strtod() for your conversions.
    They return better success/fail information.
    What do you have to say about this (i think is good):

    Code:
    //Return's 1 for success, 0 otherwise.
    int CString_ToInt(int *dst, char *string){
    
    
        //Reference where the remaining string will be stored.
        char *remaining;
    
    
        //Just Do It!
        *dst = strtol(string, &remaining, 10);
    
    
        //If there is a remaining string, BAD!
        if ( strcmp(remaining, "") != 0 )
        {
            free(remaining);
            return 0;
        }
    
    
        //Free the remaining string.
        free(remaining);
    
    
        //Return Successfully.
        return 1;
    }
    
    
    //Return's 1 for success, 0 otherwise.
    int CString_ToFloat(float *dst, char *string){
    
    
        //Reference where the remaining string will be stored.
        char *remaining;
    
    
        //Just Do It!
        *dst = (float)strtod(string, &remaining);
    
    
        //If there is a remaining string, BAD!
        if ( strcmp(remaining, "") != 0 )
        {
            free(remaining);
            return 0;
        }
    
    
        //Free the remaining string.
        free(remaining);
    
    
        //Return Successfully.
        return 1;
    }
    
    
    //Return's 1 for success, 0 otherwise.
    int CString_ToDouble(double *dst, char *string){
    
    
        //Reference where the remaining string will be stored.
        char *remaining;
    
    
        //Just Do It!
        *dst = strtod(string, &remaining);
    
    
        //If there is a remaining string, BAD!
        if ( strcmp(remaining, "") != 0 )
        {
            free(remaining);
            return 0;
        }
    
    
        //Free the remaining string.
        free(remaining);
    
    
        //Return Successfully.
        return 1;
    }

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    What on earth are all those free() calls?

    You can't free the middle of a buffer allocated with malloc. Also, you break the idea that a function should do one thing only.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  13. #13
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by Salem View Post
    What on earth are all those free() calls?

    You can't free the middle of a buffer allocated with malloc. Also, you break the idea that a function should do one thing only.
    I thought the new reference was a new memory block. So i put that free there on purpose so you can tell me if its wrong

  14. #14
    Registered User
    Join Date
    Dec 2017
    Posts
    1,628
    Quote Originally Posted by babaliaris View Post
    There is not absolute value of INT_MIN since a signed int can't represent it. Math.h documentation says that abs(INT_MIN) result is undefined and u can't expect what you will get, but has anyone solved this problem?
    The best way to handle INT_MIN is to convert int to unsigned, that way the absolute value of INT_MIN can be represented. As an example:
    Code:
    void print_int(int n) {
        unsigned u;
        if (n < 0) {
            u = -(n + 1) + 1;  // carefully convert negative to unsigned
            putchar('-');
        } else
            u = n;
        print_uint(u);
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  15. #15
    Registered User
    Join Date
    Dec 2017
    Posts
    22
    Quote Originally Posted by john.c View Post
    The best way to handle INT_MIN is to convert int to unsigned, that way the absolute value of INT_MIN can be represented. As an example:
    Code:
    void print_int(int n) {
        unsigned u;
        if (n < 0) {
            u = -(n + 1) + 1;  // carefully convert negative to unsigned
            putchar('-');
        } else
            u = n;
        print_uint(u);
    }
    Nice tip!!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Making function smaller and more efficient.
    By cmajor28 in forum C++ Programming
    Replies: 20
    Last Post: 03-19-2015, 09:03 AM
  2. More efficient way to structure this function?
    By Justin H in forum C Programming
    Replies: 8
    Last Post: 10-20-2012, 12:28 AM
  3. more efficient prime function??
    By codingGuy in forum C Programming
    Replies: 10
    Last Post: 10-12-2011, 05:09 PM
  4. Hex String to Decimal converter
    By wrex in forum C Programming
    Replies: 16
    Last Post: 11-05-2008, 06:06 PM
  5. Binary Converter - Various stupid string issues :p
    By polarpete in forum C++ Programming
    Replies: 7
    Last Post: 08-21-2005, 02:46 PM

Tags for this Thread