Thread: sence in garbage out

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    808

    sence in garbage out

    Again i have the following
    Code:
    long unsigned int StringtoNum( char [] );
    
    int main()
    {
        //declare variables
        const char cNumbers[4][51] = {
        "37107287533902102798797998220837590246510135740250",
        "46376937677490009712648124896970078050417018260538",
        "74324986199524741059474233309513058123726617309629",
        "91942213363574161572522430563301811072406154908250",
         };
    
        int i, j, k, iNumCarry;
        long unsigned int iTotal = 0, iTenDigits[4] = { 0 };
        char cStrtoNum[11] = { '\0' };
    
        for ( i = 0; i < 4; i++ )
        {
            for ( j = 40; j < 51; j++ )
            {
                cStrtoNum[j-40] = cNumbers[i][j];
            }
            iTenDigits[i] = StringtoNum( cStrtoNum );
            printf("%s %lu\n", cStrtoNum, iTenDigits[i]);
        }
    
        return 0;
    }
    
    long unsigned int StringtoNum( char strConvert[] )
    {
        long unsigned int iNumConverted = 0;
    
        iNumConverted = atoi( strConvert );
    
        return iNumConverted;
    }
    the output is as follows
    Code:
    0135740250 135740250
    7018260538 18446744072137877562
    6617309629 18446744071736926653
    6154908250 1859940954
    
    Process returned 0 (0x0)   execution time : 0.001 s
    Press ENTER to continue.
    as you can see the first number works fine the rest are utter garbage

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    4,181
    Code:
    char cStrtoNum[11] = { '\0' };
    I would try

    Code:
    char cStrtoNum[13] = { '\0' };
    Because I think your for loop is going one too much.

    Note: That would mean
    Code:
    char cStrtoNum[12] = { '\0' };
    Would be needed I did one extra in case I am wrong and your are off by two.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  3. #3
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    atoi outputs an int, not an unsigned long.
    Your values are too big for a 32-bit int and since atoi is stupid it just wraps around, potentially to a negative value representation which is then interpreted as an unsigned long, giving a large value. (The negative value is essentially added to 2**64, assuming 64-bit unsigned longs.)
    In the last case it wrapped around to a positive value.
    Note that 6154908250 % (2**31) = 1859940954 (2**31 is the largest positive 32-bit int.)
    The behavior is of course undefined, so it doesn't have to work this way. However, it typically works this way.

    atol outputs a long (but not an unsigned long).
    strtoul outputs an unsigned long, so that's the one to use here.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
     
    int main() {
        const char *numbers[4] = {
            "37107287533902102798797998220837590246510135740250",
            "46376937677490009712648124896970078050417018260538",
            "74324986199524741059474233309513058123726617309629",
            "91942213363574161572522430563301811072406154908250",
        };
        unsigned long tenDigits[4] = {0};
     
        for (int i = 0; i < 4; ++i) {
            tenDigits[i] = strtoul(numbers[i] + 40, NULL, 10);
            printf("%s %10lu\n", numbers[i] + 40, tenDigits[i]);
        }
     
        return 0;
    }
    There's more detail for properly handling errors using strtoul:
    strtoul, strtoull - cppreference.com
    Last edited by john.c; 05-26-2023 at 05:51 PM. Reason: Changed ^ to ** for exponentiation.
    All truths are half-truths. - A.N. Whitehead

  4. #4
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    wow thanks for that it help tremendously. The task was to add 100 50 digit numbers and display the first 10 digits of the answer. So i could test and for easy posting on here i just used the first 4 hence the #define N. this is the final solution.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define N 4
    
    long unsigned int StringtoNum( char [] );
    void DivideString( const char * [], char [], int, int, int );
    
    int main()
    {
        //declare variables
        const char *cNumbers[N] = {
        "37107287533902102798797998220837590246510135740250",
        "46376937677490009712648124896970078050417018260538",
        "74324986199524741059474233309513058123726617309629",
        "91942213363574161572522430563301811072406154908250",
        };
    
        int i, iNumCarry = 0, j = 50;
        long unsigned int iDivide =10000000000, iFinalTotal = 0;
        double tmpTotal = 0;
        char cStrtoNum[11] = { '\0' };
    
        do
        {
            j -= 10;
            tmpTotal += iNumCarry;
    
            if ( j > 0 )
            {
                for ( i = 0; i < N; i++ )
                {
                    DivideString( cNumbers, cStrtoNum, i, j, j + 11 );
                    tmpTotal += StringtoNum( cStrtoNum );
                }
    
                iNumCarry = tmpTotal / iDivide;
                printf("%lf %d\n", tmpTotal, iNumCarry);
                tmpTotal = 0;
            }
            else
            {
                for ( i = 0; i < N; i++ )
                {
                    DivideString( cNumbers, cStrtoNum, i, j, j + 11 );
                    tmpTotal += StringtoNum( cStrtoNum );
                }
            }
    
        } while ( j > 0 );
    
        iFinalTotal = tmpTotal / 100;
        printf("%lu\n", iFinalTotal);
    
        return 0;
    }
    
    long unsigned int StringtoNum( char strConvert[] )
    {
        long unsigned int iNumConverted = 0;
    
        iNumConverted = strtoul( strConvert, NULL, 10 );
    
        return iNumConverted;
    }
    
    void DivideString( const char *cData[], char strToConvert[], int i, int iLower, int iUpper)
    {
        //declare variable
        int j;
    
        for ( j = iLower; j < iUpper; j++ )
        {
            strToConvert[j - iLower] = cData[i][j];
        }
    
    }
    once again as always thanks for the help

  5. #5
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    Your code can be simplified to the following. Also, at least in the N=4 case, you can't be certain that the final value needs to be divided by 100. If all the numbers started with 1 then it would only need to be divided by 10.

    Note that in modern practice we don't declare all our variables at the top of a function. Instead we declare them where they are first used, in the smallest scope.

    Say "unsigned long", not "long unsigned int".

    It is generally considered idiotic to prefix variables with a type signature.

    Output variables are usually put last in a type signature.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
     
    #define N 4
     
    void substring(const char *in, int from, int to, char *out) {
        int i = from;
        for ( ; i < to; ++i) out[i - from] = in[i];
        out[i - from] = '\0';
    }
     
    int main() {
        const char *numbers[N] = {
            "37107287533902102798797998220837590246510135740250",
            "46376937677490009712648124896970078050417018260538",
            "74324986199524741059474233309513058123726617309629",
            "91942213363574161572522430563301811072406154908250",
        };
        long unsigned total = 0;
     
        for (int j = 40; j >= 0; j -= 10) {
            for (int i = 0; i < N; ++i) {
                char num[11];
                substring(numbers[i], j, j + 11, num);
                total += strtoul(num, NULL, 10);
            }
            if (j > 0)
                total /= 10000000000UL;
        }
     
        while (total >= 10000000000UL) total /= 10;
        printf("%lu\n", total);
     
        return 0;
    }
    You could replace the substring function with an sprintf call:
    Code:
    sprintf(num, "%.10s", numbers[i] + j);
    All truths are half-truths. - A.N. Whitehead

  6. #6
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    i tried your suggestion of having variables with the smallest scope on a different problem and for 5 for loops i had to declare i 4 times. is this the correct practice or if i know i'm going to use a variable multiple times for multiple for loops or the like should i just declare it once and be done with it

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    is this the correct practice
    Yes. Remember to do it like this:
    Code:
    for (int i = 0; i < 10; ++i) ...
    All truths are half-truths. - A.N. Whitehead

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting garbage value
    By Collin Heeb in forum C++ Programming
    Replies: 1
    Last Post: 12-16-2020, 10:56 PM
  2. Getting Garbage Value
    By notGrandiose in forum C++ Programming
    Replies: 9
    Last Post: 01-21-2014, 02:09 AM
  3. garbage value
    By parvathi in forum C Programming
    Replies: 6
    Last Post: 12-29-2013, 03:36 AM
  4. Garbage appearing
    By DeanWinchester in forum C Programming
    Replies: 3
    Last Post: 05-27-2012, 02:47 PM
  5. Garbage Collection in C++
    By Warlax in forum C++ Programming
    Replies: 4
    Last Post: 09-30-2006, 07:10 PM

Tags for this Thread