-1

I have been trying this popular question, where I have to multiply two very large numbers in C (without using any libraries other than stdio.h). I know my algorithm and code are correct, since it works on dry runs.

However, the ans array here keeps allocating itself garbage value, to which I cannot find any reason whatsoever.

The input format is number1 * number2

Following is my code:

#include <stdio.h>

int main(){

char str[200];
gets(str);

int length = 0;
for (int i = 0; ; i++){

    if(str[i]=='\0'){
        break;
    }

    length++;
}


int s1[101], s2[101];
int l1 = 0, l2 = 0, temp = 0;

for(int i = 0; i<length; i++){
    l1++;
    if(str[i]=='*'){
        l1-=2;
        temp = i;
        break;
    }
}

l2 = length-l1;
l2-=3;


for(int i = 0; i<l1; i++){
    s1[i] = str[i]-'0';
}
for(int i = l1+3; i<length; i++){
    s2[i] = str[i]-'0';
}


int a[100],b[100];
int ans[200];
int i,j,tmp;

for(int k = 0; i<200; i++){
    ans[k] = 0;
}

 j = l1 - 1;  
 i = 0;       

while (i < j){
  tmp = s1[i];
  s1[i] = s1[j];
  s1[j] = tmp;
  i++;             
  j--;         
}


j = l2 - 1;  
 i = 0;       

while (i < j){
  tmp = s2[i];
  s2[i] = s2[j];
  s2[j] = tmp;
  i++;             
  j--;         
}

for(i = 0;i < l2;i++){
    for(j = 0;j < l1;j++){
        ans[i+j] += s2[i]*s1[j];
        printf(" %d", ans[i+j]);
    }
}
for(i = 0;i < l1+l2;i++)
{
    tmp = ans[i]/10;
    ans[i] = ans[i]%10;
    ans[i+1] = ans[i+1] + tmp;
}
for(i = l1+l2; i>= 0;i--)
{
    if(ans[i] > 0)
        break;
}
//printf("Product : ");
for(;i >= 0;i--)
{
   //printf("%d",ans[i]);
}
return 0;
}

Can anyone help me out with this problem and tell me why this garbage value comes, and how to avoid this error?

  • 1
    `for(int k = 0; i<200; i++){` This is one problem - replace `i` with `k`! Another problem is `for(int i = l1+3; i – kiner_shah Aug 11 '18 at 15:12
  • 2
    Don't use `gets()` — [`gets()` is too dangerous to be used, ever!](https://stackoverflow.com/questions/1694036/). Your `for` loop — _`for (int i = 0; ; i++){ if(str[i]=='\0'){ break; } length++; }`_ — is eccentric; place the condition of the `if` in the condition of the loop. In fact, you should just iterate using `length` without using `i` at all, reducing the code to `for (length = 0; str[length] != '\0'; length++) ;` where the trailing semicolon should be an empty loop body on the next line. Using 6 lines where 2 would do is a tad wasteful. – Jonathan Leffler Aug 11 '18 at 16:59

1 Answers1

3

Red herring

The original code used int ans[200] = { 0 }; but in the light of some comments, that was changed to:

int ans[200];
for (int k = 0; i < 200; i++){
    ans[k] = 0;
}

The loop is clearly erroneous; the index k should be tested and incremented, not i.

However, the original code was correct — it initializes all the elements of the array to 0 as desired. I'm sorry you got a 'bum steer' from some of the commentators.

Diagnosis

I think your main problem is in converting the second number into a string of digits.

for (int i = l1 + 3; i < length; i++){
    s2[i] = str[i] - '0';
}

You need to assign to indexes in s2 in the range 0..l2, but you are indexing starting from l1+3, which leaves the start of s2 holding garbage. In the solution below, I took a lazy (but effective) way out: I created int z = 0; before the loop, and used s2[z++] = str[i] - '0';.

(Now I go back and reread kiner_shah's comment, I see that comment also diagnosed this flaw – but I confess I didn't understand what was said until re-reviewing the comments after posting this answer.)

Prescription

I added some assertions to ensure that things behaved as I expected. I added extensive debug printing. I also renamed l1 to len1 and l2 to len2; the 2-character names are just too easily confused with 11 and 12. I created a printing function to show the converted numbers. I could/should have created a function to encapsulate the conversion process.

The main problem was easily spotted when a simple test printed zeros for the second number, even though I'd typed 123 as the number. It was coincidence that it was zeros; the key point is that it wasn't 123 as expected.

Note that the printing has to deal with the special case of 0 as the result. The code that converts the string into a series of decimal digits could spot whether all the digits are zero (simply sum the converted digits; if the result is zero, all the digits are zero) and then special case the calculation (zero times anything is zero).

#include <assert.h>
#include <stdio.h>

/* Print digits - ensure each digit is visible with parentheses */
static void print_number(const char *tag, int len, int data[len])
{
    printf("Number %s: [", tag);
    for (int i = 0; i < len; i++)
        printf("(%d)", data[i]);
    printf("]\n");
}

int main(void)
{
    char str[200];
    if (fgets(str, sizeof(str), stdin) == NULL)
        return 1;

    int length;
    for (length = 0; str[length] != '\0' && str[length] != '\n'; length++)
        ;
    str[length] = '\0';     /* Zap newline */

    printf("Calculation: [%s]\n", str);                 // Debug

    int s1[101], s2[101];
    int len1 = 0, len2 = 0;

    /* This is fragile - it depends on the user getting the format right! */
    for (int i = 0; i < length; i++)
    {
        len1++;
        if (str[i] == '*')
        {
            len1 -= 2;
            break;
        }
    }
    assert(str[len1+0] == ' ');                         // Debug
    assert(str[len1+1] == '*');                         // Debug
    assert(str[len1+2] == ' ');                         // Debug

    len2 = length - len1;
    len2 -= 3;

    printf("Number 1: [%.*s]\n", len1, str);            // Debug
    printf("Number 2: [%.*s]\n", len2, &str[len1 + 3]); // Debug

    for (int i = 0; i < len1; i++)
    {
        assert(str[i] >= '0' && str[i] <= '9');         // Debug
        s1[i] = str[i] - '0';
    }
    print_number("1A", len1, s1);                       // Debug
    int z = 0;
    for (int i = len1 + 3; i < length; i++)
    {
        assert(str[i] >= '0' && str[i] <= '9');         // Debug
        s2[z++] = str[i] - '0';
    }
    print_number("2A", len2, s2);                       // Debug

    int ans[200] = { 0 };
    int i, j, tmp;

    /* Reverse digits of first number */
    /* Need a function for this! */
    j = len1 - 1;
    i = 0;
    while (i < j)
    {
        tmp = s1[i];
        s1[i] = s1[j];
        s1[j] = tmp;
        i++;
        j--;
    }

    /* Reverse digits of second number */
    j = len2 - 1;
    i = 0;
    while (i < j)
    {
        tmp = s2[i];
        s2[i] = s2[j];
        s2[j] = tmp;
        i++;
        j--;
    }

    /* Raw multiplication - deal with carries later */
    for (i = 0; i < len2; i++)
    {
        for (j = 0; j < len1; j++)
        {
            ans[i + j] += s2[i] * s1[j];
            printf("[%d+%d] = %d\n", i, j, ans[i + j]);
        }
    }

    /* Deal with carries */
    for (i = 0; i < len1 + len2; i++)
    {
        int old1 = ans[i];                              // Debug
        int old2 = ans[i+1];                            // Debug
        tmp = ans[i] / 10;
        ans[i] = ans[i] % 10;
        ans[i + 1] = ans[i + 1] + tmp;
        printf("Fixup %d: old (%d)(%d) new (%d)(%d)\n", // Debug
               i, old1, old2, ans[i], ans[i+1]);        // Debug
    }

    /* Find most significant digit */
    for (i = len1 + len2; i >= 0; i--)
    {
        if (ans[i] > 0)
            break;
    }
    printf("Significant digits = %d\n", i + 1);         // Debug

    /* Print digits in reverse order */
    j = i;      // Save starting point in j             // Debug
    if (i == -1)                                        // Debug
        putchar('0');                                   // Debug
    else                                                // Debug
    {                                                   // Debug
        printf("Product : ");                           // Debug
        for ( ; i >= 0; i--)                            // Debug
        {                                               // Debug
            printf("(%d)", ans[i]);                     // Debug
        }                                               // Debug
    }                                                   // Debug
    putchar('\n');                                      // Debug
    i = j;      // Recover starting point from j        // Debug

    printf("Product : ");
    if (i == -1)
        putchar('0');
    else
    {
        for ( ; i >= 0; i--)
        {
            printf("%d", ans[i]);
        }
    }
    putchar('\n');

    return 0;
}

Sample test runs

Calculate 98 x 123

Calculation: [98 * 123]
Number 1: [98]
Number 2: [123]
Number 1A: [(9)(8)]
Number 2A: [(1)(2)(3)]
[0+0] = 24
[0+1] = 27
[1+0] = 43
[1+1] = 18
[2+0] = 26
[2+1] = 9
Fixup 0: old (24)(43) new (4)(45)
Fixup 1: old (45)(26) new (5)(30)
Fixup 2: old (30)(9) new (0)(12)
Fixup 3: old (12)(0) new (2)(1)
Fixup 4: old (1)(0) new (1)(0)
Significant digits = 5
Product : (1)(2)(0)(5)(4)
Product : 12054

Calculate 987654321 x 123456789012

Calculation: [987654321 * 123456789012]
Number 1: [987654321]
Number 2: [123456789012]
Number 1A: [(9)(8)(7)(6)(5)(4)(3)(2)(1)]
Number 2A: [(1)(2)(3)(4)(5)(6)(7)(8)(9)(0)(1)(2)]
[0+0] = 2
[0+1] = 4
[0+2] = 6
[0+3] = 8
[0+4] = 10
[0+5] = 12
[0+6] = 14
[0+7] = 16
[0+8] = 18
[1+0] = 5
[1+1] = 8
[1+2] = 11
[1+3] = 14
[1+4] = 17
[1+5] = 20
[1+6] = 23
[1+7] = 26
[1+8] = 9
[2+0] = 8
[2+1] = 11
[2+2] = 14
[2+3] = 17
[2+4] = 20
[2+5] = 23
[2+6] = 26
[2+7] = 9
[2+8] = 0
[3+0] = 20
[3+1] = 32
[3+2] = 44
[3+3] = 56
[3+4] = 68
[3+5] = 80
[3+6] = 72
[3+7] = 72
[3+8] = 81
[4+0] = 40
[4+1] = 60
[4+2] = 80
[4+3] = 100
[4+4] = 120
[4+5] = 120
[4+6] = 128
[4+7] = 145
[4+8] = 72
[5+0] = 67
[5+1] = 94
[5+2] = 121
[5+3] = 148
[5+4] = 155
[5+5] = 170
[5+6] = 194
[5+7] = 128
[5+8] = 63
[6+0] = 100
[6+1] = 133
[6+2] = 166
[6+3] = 179
[6+4] = 200
[6+5] = 230
[6+6] = 170
[6+7] = 111
[6+8] = 54
[7+0] = 138
[7+1] = 176
[7+2] = 194
[7+3] = 220
[7+4] = 255
[7+5] = 200
[7+6] = 146
[7+7] = 94
[7+8] = 45
[8+0] = 180
[8+1] = 202
[8+2] = 232
[8+3] = 271
[8+4] = 220
[8+5] = 170
[8+6] = 122
[8+7] = 77
[8+8] = 36
[9+0] = 205
[9+1] = 238
[9+2] = 280
[9+3] = 232
[9+4] = 185
[9+5] = 140
[9+6] = 98
[9+7] = 60
[9+8] = 27
[10+0] = 240
[10+1] = 284
[10+2] = 238
[10+3] = 193
[10+4] = 150
[10+5] = 110
[10+6] = 74
[10+7] = 43
[10+8] = 18
[11+0] = 285
[11+1] = 240
[11+2] = 196
[11+3] = 154
[11+4] = 115
[11+5] = 80
[11+6] = 50
[11+7] = 26
[11+8] = 9
Fixup 0: old (2)(5) new (2)(5)
Fixup 1: old (5)(8) new (5)(8)
Fixup 2: old (8)(20) new (8)(20)
Fixup 3: old (20)(40) new (0)(42)
Fixup 4: old (42)(67) new (2)(71)
Fixup 5: old (71)(100) new (1)(107)
Fixup 6: old (107)(138) new (7)(148)
Fixup 7: old (148)(180) new (8)(194)
Fixup 8: old (194)(205) new (4)(224)
Fixup 9: old (224)(240) new (4)(262)
Fixup 10: old (262)(285) new (2)(311)
Fixup 11: old (311)(240) new (1)(271)
Fixup 12: old (271)(196) new (1)(223)
Fixup 13: old (223)(154) new (3)(176)
Fixup 14: old (176)(115) new (6)(132)
Fixup 15: old (132)(80) new (2)(93)
Fixup 16: old (93)(50) new (3)(59)
Fixup 17: old (59)(26) new (9)(31)
Fixup 18: old (31)(9) new (1)(12)
Fixup 19: old (12)(0) new (2)(1)
Fixup 20: old (1)(0) new (1)(0)
Significant digits = 21
Product : (1)(2)(1)(9)(3)(2)(6)(3)(1)(1)(2)(4)(4)(8)(7)(1)(2)(0)(8)(5)(2)
Product : 121932631124487120852
$ bc <<< '987654321 * 123456789012'
121932631124487120852
$

Calculate 000 x 0000

Calculation: [000 * 0000]
Number 1: [000]
Number 2: [0000]
Number 1A: [(0)(0)(0)]
Number 2A: [(0)(0)(0)(0)]
[0+0] = 0
[0+1] = 0
[0+2] = 0
[1+0] = 0
[1+1] = 0
[1+2] = 0
[2+0] = 0
[2+1] = 0
[2+2] = 0
[3+0] = 0
[3+1] = 0
[3+2] = 0
Fixup 0: old (0)(0) new (0)(0)
Fixup 1: old (0)(0) new (0)(0)
Fixup 2: old (0)(0) new (0)(0)
Fixup 3: old (0)(0) new (0)(0)
Fixup 4: old (0)(0) new (0)(0)
Fixup 5: old (0)(0) new (0)(0)
Fixup 6: old (0)(0) new (0)(0)
Significant digits = 0
0
Product : 0

Observations on making debugging easier

This should get you going; there's a lot of refinements that could/should be made. This preserves most of your original code. It also shows you how I added code — assertions and printing operations — to see what was going on. When I saw this as the output from an early version of the code:

Calculation: [98 * 123]
Number 1: [98]
Number 2: [123]
Number 1A: [(9)(8)
Number 2A: [(0)(0)(0)
[0+0] = 0
[0+1] = 0
[1+0] = 0
[1+1] = 0
[2+0] = 0
[2+1] = 0
Fixup 0: old (0)(0) new (0)(0)
Fixup 1: old (0)(0) new (0)(0)
Fixup 2: old (0)(0) new (0)(0)
Fixup 3: old (0)(0) new (0)(0)
Fixup 4: old (0)(0) new (0)(0)
Significant digits = -1
Product : 

it was easy to see where there was a problem (the second conversion loop), and from there it was easy to diagnose the main problem. When debugging, print inputs to make sure the program got what you expected. Print intermediate results to check that you get what you expected. Print final results carefully — make sure you are getting what you think you're getting. The use of (%d) illustrates the 'be careful'; when printing a digit string, it would have been easy to spot (19) is wrong whereas just 19 could be right or wrong, depending.

I'll also point you towards C #define macro for debug printing for information on how I'd use conditional compilation to deal with the debug printing if it was going to remain a useful part of a long-term program. You can find the relevant code in my SOQ (Stack Overflow Questions) repository on GitHub as files debug.c and debug.h in the src/libsoq sub-directory.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278