簡體   English   中英

為什么C中的此數組不斷為其分配垃圾值?

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

我一直在嘗試這個普遍的問題,我必須在C中將兩個非常大的數字相乘(不使用stdio.h以外的任何庫)。 我知道我的算法和代碼是正確的,因為它適用於空運行。

但是,這里的ans數組會不斷分配自身的垃圾值,我找不到任何原因。

輸入格式為number1 * number2

以下是我的代碼:

#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;
}

誰能幫我解決這個問題,並告訴我為什么會出現此垃圾值,以及如何避免此錯誤?

紅鯡魚

原始代碼使用int ans[200] = { 0 }; 但根據一些評論,將其更改為:

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

循環顯然是錯誤的。 索引k應該被測試並增加,而不是i

但是,原始代碼是正確的-根據需要將數組的所有元素初始化為0 對不起,您對某些評論員不滿意。

診斷

我認為您的主要問題是將第二個數字轉換為數字字符串。

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

您需要在s2中的索引中分配范圍為0 .. l2 ,但是您要從l1+3開始進行索引,這使s2的開始保留了垃圾。 在下面的解決方案中,我采取了一種懶惰(但有效)的方法:創建了int z = 0; 在循環之前,並使用s2[z++] = str[i] - '0';

(現在,我回去重新閱讀kiner_shah評論 ,我看到該評論也診斷出了這個缺陷-但我承認直到發布此答案后重新審閱評論,我才明白自己的意思。)

處方

我添加了一些斷言,以確保一切正常。 我添加了廣泛的調試打印。 我也將l1重命名為len1 ,將l2重命名為len2 2個字符的名稱很容易與1112混淆。 我創建了一個打印功能來顯示轉換后的數字。 我可以/應該已經創建了一個函數來封裝轉換過程。

當一個簡單的測試為第二個數字打印零時,即使我鍵入123作為數字,也很容易發現主要問題。 巧合的是,它為零。 關鍵是它不是預期的123

請注意,打印結果必須處理特殊情況0。 將字符串轉換為一系列十進制數字的代碼可以發現所有數字是否均為零(簡單地將轉換后的數字相加;如果結果為零,則所有數字均為零),然后在特殊情況下進行計算(零乘以除以零)。

#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;
}

樣品測試運行

計算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

計算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
$

計算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

關於簡化調試的觀察

這應該可以幫助您前進; 有很多可以/應該做的改進。 這將保留大多數原始代碼。 它還顯示了如何添加代碼(斷言和打印操作)以查看發生了什么。 當我將其視為早期版本代碼的輸出時:

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 : 

很容易看到問題出在哪里(第二個轉換循環),從那里很容易診斷出主要問題。 調試時,打印輸入以確保程序符合您的期望。 打印中間結果以檢查您是否達到了預期。 仔細打印最終結果-確保獲得想要的東西。 (%d)說明了“小心”; 當打印數字字符串時,很容易發現(19)是錯誤的,而視情況而定,只有19是對還是錯。

我還將向您介紹用於調試打印的C #define宏,以獲取有關如何使用條件編譯來處理調試打印(如果它仍將是長期程序的有用部分)的信息。 您可以在GitHub上的我的SOQ (堆棧溢出問題)存儲庫中找到相關代碼, debug.hsrc / libsoq子目錄中找到debug.cdebug.h文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM