【问题标题】:C - Print ArrayC - 打印数组
【发布时间】:2015-11-11 19:20:12
【问题描述】:

我正在尝试实时打印添加到数组中的元素 .

一切似乎都很好,但是

例如

我将数字 1 2 3 相加

但结果是: 9966656 2686588 1 2 3

我不知道为什么它也打印 9966656 2686588 而不仅仅是 1 2 3

    int numbers[100] , c , x;
    char answer;
    puts("Please insert a value");

GO:
    scanf("%d", &numbers[c]);
    getchar();
    puts("Do you want to add another value? y/n");
    scanf("%c",&answer);
    if (answer == 'y') {
        c = c + 1;
        puts("Please insert another value");
        goto GO;
    } else {
        x = c;

        for (c = 0; c < x + 1; c++) {
            printf("%d ",numbers[c]);
        }
    }

*======================

如果你有什么不明白的地方请告诉我*

【问题讨论】:

  • 在捕获输入之前,您不会丢弃空白,还要注意 goto 的使用:-P
  • 尝试在顶部初始化c = 0
  • c 在您扫描 numbers[c] 时未初始化。将其设置为 0 并确保当 c 达到 100 时不会溢出数组。
  • 如果您认为需要goto,您可能会发现代码组织方面的改进空间。
  • 有很多方法可以避免 goto。

标签: c arrays printf


【解决方案1】:

您需要解决几个问题。如果您使用 Warnings Enabled 进行编译(例如,将 -Wall -Wextra 添加到您的编译字符串中),所有这些都会为您拼写出来。例如:

$ gcc -Wall -Wextra -o bin/go go.c

go.c: In function ‘main’:
go.c:17:5: warning: format ‘%c’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[30]’ [-Wformat=]
 scanf("%c",&answer);
 ^
go.c:18:15: warning: comparison between pointer and integer [enabled by default]
 if(answer == 'y')

如果您解决每个警告,直到您的代码在没有警告的情况下编译,您就会遇到主要问题:

for(c = 0; c < x + 1; c++)

x + 1 导致您的循环读取数据末尾之外的内容。由于您NOT 初始化了numbers,因此它正在读取默认情况下存在的垃圾值。这是另一个很好的教训:总是初始化你的变量

您在管理xc 的方式上也会遇到问题。 c 应仅在用户成功转换小数时更新,如 scanf 所读取。 scanf 返回时提供成功转换的次数。您需要使用返回来检查用户输入的有效小数,然后仅在成功转换时更新c(而不是用户输入y/n 的结果。

稍微清理一下,将您的逻辑稍微重新安排为类似于以下内容会更好:

#include <stdio.h>

int main (void) {

    int numbers[100] = { 0 };
    int c = 0;
    int i = 0;
    char answer[30] = { 0 };

    printf (" Please insert a value: ");

GO:

    if (scanf ("%d", &numbers[c]) == 1)
        c++;
    getchar ();
    printf (" Do you want to add another value (y/n)? ");
    scanf ("%c", answer);
    if (*answer == 'y') {
        printf (" Please insert another value: ");
        goto GO;
    }

    for (i = 0; i < c; i++) {
        printf (" number[%2d] : %d\n", i, numbers[i]);
    }

    return 0;
}

输出

$ ./bin/go
 Please insert a value: 10
 Do you want to add another value (y/n)? y
 Please insert another value: 11
 Do you want to add another value (y/n)? y
 Please insert another value: 12
 Do you want to add another value (y/n)? n
 number[ 0] : 10
 number[ 1] : 11
 number[ 2] : 12

(注意:我将 x 更改为 i - 只是觉得迭代 i 更正常)

【讨论】:

    【解决方案2】:

    该行为未定义,因为c 未初始化,您将其用作“索引”(&amp;numbers[c])。这也可能导致分段错误,甚至按您的预期行事。

    你需要做的是一开始就将c设置为0。

    另外请尽量避免使用goto,除非有真正合理的理由使用它。

    【讨论】:

    • 我已经编程了将近 40 年。我在 BASIC 中学习了 goto,并且可能在 C 中简单地使用过它。在我剩下的开发年限中,我从未见过需要 goto。我已经看到它在内核开发中被仔细而清晰地用作约定,但仍然没有看到实际需要。它被滥用了,所以我总能找到更好的方法。
    • 非常感谢您的回答。 标记
    • @ehem,通过“滥用”,我的意思是它可以用来控制在需要的地方流动,但是以非常混乱的方式。总的来说,它向我表明有人还没有明确决定是for 循环是最好的,还是while,还是do ... while。总有比goto 更好的方法,如果您使用goto(内核开发例外),您代码的未来维护者将不会喜欢您的工作。
    • @donjuedo 我还看到goto 使用长流和各种资源管理。每次获取/获取资源时,都会设置一个特定的布尔标志。一旦流程未能获取资源或由于任何其他原因失败,它使用goto 跳转到流程的末尾并根据布尔标志释放所有获取/获取的资源(它告诉哪些资源被占用以及哪个不是)。 securecoding.cert.org/confluence/display/c/…
    • @AlexLop.,我知道您所指的技术。当我看到它时,我检查它是否按照您所说的严格使用,然后我继续前进。但是,没有goto,也有完成该任务的等效方法。我不会说“更好”,因为至少这种使用是有纪律的。但“等价”是公平的。
    猜你喜欢
    • 2014-05-20
    • 2013-09-23
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多