简体   繁体   English

为什么C中的此数组不断为其分配垃圾值?

[英]Why does this array in C keeps assigning garbage value to itself?

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). 我一直在尝试这个普遍的问题,我必须在C中将两个非常大的数字相乘(不使用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. 但是,这里的ans数组会不断分配自身的垃圾值,我找不到任何原因。

The input format is number1 * number2 输入格式为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? 谁能帮我解决这个问题,并告诉我为什么会出现此垃圾值,以及如何避免此错误?

Red herring 红鲱鱼

The original code used int ans[200] = { 0 }; 原始代码使用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 . 索引k应该被测试并增加,而不是i

However, the original code was correct — it initializes all the elements of the array to 0 as desired. 但是,原始代码是正确的-根据需要将数组的所有元素初始化为0 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. 您需要在s2中的索引中分配范围为0 .. l2 ,但是您要从l1+3开始进行索引,这使s2的开始保留了垃圾。 In the solution below, I took a lazy (but effective) way out: I created int z = 0; 在下面的解决方案中,我采取了一种懒惰(但有效)的方法:创建了int z = 0; before the loop, and used s2[z++] = str[i] - '0'; 在循环之前,并使用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.) (现在,我回去重新阅读kiner_shah评论 ,我看到该评论也诊断出了这个缺陷-但我承认直到发布此答案后重新审阅评论,我才明白自己的意思。)

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 ; 我也将l1重命名为len1 ,将l2重命名为len2 the 2-character names are just too easily confused with 11 and 12 . 2个字符的名称很容易与1112混淆。 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. 当一个简单的测试为第二个数字打印零时,即使我键入123作为数字,也很容易发现主要问题。 It was coincidence that it was zeros; 巧合的是,它为零。 the key point is that it wasn't 123 as expected. 关键是它不是预期的123

Note that the printing has to deal with the special case of 0 as the result. 请注意,打印结果必须处理特殊情况0。 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 计算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 计算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 计算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'; (%d)说明了“小心”; when printing a digit string, it would have been easy to spot (19) is wrong whereas just 19 could be right or wrong, depending. 当打印数字字符串时,很容易发现(19)是错误的,而视情况而定,只有19是对还是错。

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. 我还将向您介绍用于调试打印的C #define宏,以获取有关如何使用条件编译来处理调试打印(如果它仍将是长期程序的有用部分)的信息。 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. 您可以在GitHub上的我的SOQ (堆栈溢出问题)存储库中找到相关代码, debug.hsrc / libsoq子目录中找到debug.cdebug.h文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM