【问题标题】:How to fix infinite printing of random number?如何修复随机数的无限打印?
【发布时间】:2019-05-02 20:52:07
【问题描述】:

我编写了一个程序,它将未知数量的整数扫描到一个数组中,但是当我运行它时,它会无限次打印它获得的最后一个值。

例如对于输入:1 2 3 4 5

输出将是 55555555555555555555555...

为什么会发生这种情况,我该如何解决?

我的目标是创建一个数组,例如 {1, 2, 3, 4, 5},然后将扫描到的内容打印到数组中,仅一次...

int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");

scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
    pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
    if(pSet == NULL) {
        return FAIL;        
    }
    scanf("%d", &c);
    pSet[i] = c;
    printf("%d ", c);
}

free(pSet);

【问题讨论】:

  • 你永远不会检查scanf()是否真的有效。
  • 我尝试根据您发送的内容修复我的输入,但它并没有改变任何东西。我发送给程序:1 2 3 4 5 (Enter) (Enter) @BurnsBA
  • 如果 scanf() 不起作用,则变量 c 不会被初始化。程序打印 c,在打印 c 时为 5。我几乎不认为这是问题所在……但无论如何,谢谢! @AndrewHenle
  • 这几行主要是自包含代码中的一个问题是生来调试器中单步执行。并且停止忽略那些scanf 调用的结果,以免你违反Spencer's Sixth Commandment。最后,我挑战你指出,在documentation for scanf 中,它声明一旦流达到相同的状态(因为不存在这种行为),它会使用EOF 填充整数格式的输出参数。简短版:阅读并理解您正在使用的功能的要求
  • 删除了不必要的“[未解决]”标题编辑。解决了还是没解决,标题不用改。

标签: c loops printf command-line-interface scanf


【解决方案1】:

您应该在 scanf 失败时停止循环。根据手册

成功时,[scanf] return[s] 成功匹配并分配的输入项数;如果发生早期匹配失败,这可能会小于规定的值,甚至为零。 如果在第一次成功转换或匹配失败发生之前到达输入结尾,则返回值 EOF。如果发生读取错误,也会返回 EOF。 [...]

所以你可以把你的 for 循环变成一个 while 循环。

#include <stdio.h>
#include <stdlib.h>

#define FAIL 0
int main() {
  int *pSet = (int*) malloc(sizeof(int));
  int c;
  int i=0;
  printf("Please enter a stream of numbers to make a set out of them: ");
  while(scanf("%d", &c) == 1) {
    pSet[i] = c;
    pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
    if(pSetNew == NULL) {
      free(pSet);
      return FAIL;        
    } else {
      pSet = pSetNew;
    }
    printf("%d ", c);
    i++;
  }

  free(pSet);
}

但是,如果您想要一段更健壮的代码,我建议您将答案检索为字符串(NULL-终止的数组 char),然后使用 strtol 等专用函数对其进行解析您检查 整个 字符串是否是有效条目,而不仅仅是第一个字符。

注意:HengLi 修复了上述代码示例中潜在的内存泄漏

【讨论】:

  • *** `./catch' 中的错误:realloc():下一个大小无效:0x088c8008 *** @Amessihel
  • @ShadowOverLoad 最好搜索与此问题相关的现有答案,或者提出准确描述您的环境的新问题,以避免创建重复。
  • 代码中可能存在内存泄漏问题。当 realloc 找不到足够的空间来分配时,它返回一个 NULL 并保持原来分配的空间。这个example 展示了如何通过使用新变量来保存 realloc 的返回来解决问题。
【解决方案2】:

有很多问题。

1) 当scanf 失败时终止循环,而不是使用 EOF。通过检查返回值是否为 1(即输入项的数量 匹配成功)

2) 在需要之前不要分配内存

3) 从不realloc 直接插入目标指针 - 始终使用临时变量。

解决这个问题你的代码可能是:

#include <stdio.h>

int main(void) {
    int *pSet = NULL;
    printf("Please enter a stream of numbers to make a set out of them: ");
    printf("\n");

    int i = 0;
    int c;
    while (1) {
         if (scanf("%d", &c) != 1)
         {
             printf("Terminating input loop\n");
             break;
         }

         int* tmp = realloc(pSet, sizeof(int)*(i+1));
         if(tmp == NULL) {
            printf("oh dear...\n");
            break;
         }
         pSet = tmp;
         pSet[i++] = c;
         printf("%d ", c);
    }

    for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
    free(pSet);
    return 0;
}

输入:

1 2 3 4 5 6 7 stop

输出:

Please enter a stream of numbers to make a set out of them: 
1 2 3 4 5 6 7 
Terminating input loop
1
2
3
4
5
6
7

【讨论】:

  • realloc in temp(第 17 行)每次都失败。 @4386427
  • ideone.com/XR4tQt我改了你的代码,你写的有些东西不是按照C语法的。 @4386427
  • @ShadowOverLoad 您具体发现了什么不是“不符合 C 语法”?您正在使用哪个当前版本的 C?我怀疑这是20年前的版本。这个答案是有效的 C.
  • @ShadowOverLoad "不符合 C 语法" 什么?请澄清
  • 我在修复后发送了代码。例如,在 C 语言中,编译器不会让您在循环中一次定义和初始化所有内容,就像您对数组 tmp 所做的那样。 @4386427
【解决方案3】:

为什么会发生这种情况(?)(打印...无限次。)

查看循环终止条件c != EOF

int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) {  // Not good code
  scanf("%d", &c);
}

EOF 是一些负值,通常是 -1。 scanf("%d", &amp;c) 尝试读取用户输入并转换为 intscanf() 返回 1,0,EOF,具体取决于 1) 成功,2) 找不到数字文本或 3) 文件结束或输入错误。不幸的是,代码不使用该返回值。相反,代码使用读取的数字c 并检查读取的数字是否与EOF 相同。


我该如何解决这个问题?

仅当scanf() 的返回值符合预期(1)时才循环。

for(i = 1; scanf("%d", &c) == 1; i++) {
  ...
}

把这个和其他一些想法放在一起

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

int main(void) {
  printf("Please enter a stream of numbers to make a set out of them:\n");
  int *pSet = NULL;  // Start with no allocation
  size_t i = 0;

  int c;
  for (i = 0; scanf("%d", &c) == 1; i++) {
    //        +---------------------------  No cast needed.
    //        v               v----------v  Use sizeof de-referenced pointer
    void *p =   realloc(pSet, sizeof *pSet * (i + 1));
    if (p == NULL) {
      free(pSet);
      return EXIT_FAILURE;
    }
    pSet = p;
    pSet[i] = c;
  }

  for (size_t j = 0; j < i; j++) {
    printf("%d ", pSet[j]);
  }

  free(pSet);
  return 0;
}

【讨论】:

  • 对于输入 1 2 3 4 5,输出为:1 0 2 130017 3 130009 4 130001 5 129993 @chux
  • @ShadowOverLoad 代码已修改 - 删除额外的 ++
猜你喜欢
  • 2021-12-15
  • 2015-01-11
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 2020-02-11
  • 1970-01-01
  • 1970-01-01
  • 2011-12-08
相关资源
最近更新 更多