【问题标题】:I have a problem with "The 3n+1 problem".when i debug it我对“3n+1 问题”有疑问。当我调试它时
【发布时间】:2019-02-19 05:06:46
【问题描述】:

我尝试解决“3n+1”问题。 当我调试我的代码时,它停留在第 12 行,计算函数。 “根据 Collat​​z 猜想,j 应该收敛到 1。”

主文件

    #include "input_output.h"
    #include <stdlib.h>
    int main() {
        int i=0, j=0;`
        int *num;
        int maxCycle;
        int length;
        input(&i, &j);
        length = j - i + 1;
        num = (int*)malloc(sizeof(int)*(j - i+1));

这是问题代码

        while (i <= j) {            
            calculate(j, num);//<- it stuck at here when i dubug it.
            j--;                    
            num++;                  
        }

        maxCycle = findMax(length, num);
        output(maxCycle);
        return 0;
    }

源文件

    #include <stdio.h>
    #include "input_output.h"
    #pragma warning (disable:4996)
    void input(int *i, int *j) {
        scanf("%d %d", i,j);    
    }

    void calculate(int j, int* num) {

        while (j > 1) {     
            if (j % 2 == 0) {   
                j = j / 2;
                *num++;         
            }

            if (j % 2 == 1) {   
                j = j * 3 + 1;  
                *num++;         
            }
        }
    }

    int findMax(int length, int * num){
        int max = 0;
        int idx = 0;
        while (idx < length) {
            if (*num > max) max = *num;
            idx++;
            num++;
        }
        return max;

    }

    void output(int maxout) {
        printf("%d", maxout);
    }

标题

    #ifndef __input_output_H__
    #define __input_output_H__

    void input(int *i, int *j);         
    void calculate(int j,int *num); 
    int findMax(int length, int* num);
    void output(int maxout);



    #endif __input_output_H__

我认为标题似乎没有问题,而且主文件也是如此。 我的源文件有问题吗? 我想知道为什么调试器会卡在那里......

【问题讨论】:

  • 如果你的calculate()函数应该返回达到1的迭代次数,也许函数返回类型应该是int(或size_t,或unsigned long long)将指针传递给函数并返回类型为void。此外,重复的(*num)++ 比增加局部变量要慢——也许不是那么慢,但可能慢得多。而且,当然,您需要添加括号——当您增加指针而不是增加指针指向的位置时,您当前正在访问未知位置。
  • 请注意,一般情况下,您不应创建以下划线开头的函数、变量、标记或宏名称。 C11 §7.1.3 Reserved identifiers 的一部分说: — 以下划线开头的所有标识符以及大写字母或另一个下划线始终保留用于任何用途。所有以下划线开头的标识符始终保留保留用作普通和标记名称空间中具有文件范围的标识符。 另见What does double underscore (__const) mean in C?
  • 您遇到了问题,因为您在 main 函数中分配了 num 指向的数组,然后重复增加该指针,因此您无法跟踪数组的开始位置。但是你真的不需要数组;您只需要当前整数的周期数以及到目前为止找到的最大长度。你泄露了数组,因为你没有调用free()——尽管考虑到你已经丢失了malloc()返回的值,目前,这是一件好事!
  • Definitive C Book Guide and List。我推荐 K.N.King 的书。
  • 感谢您非常详细地批评了我的代码。顺便问一下,如果不是借口,你能推荐一本学习C的书吗?我正在尝试在 C Programming : A Modern Approach 由 K.N.King 编写和 The C Programming Language 由 Dennis Ritchie 编写之间选择一本书。或者有没有更好的书适合我?

标签: c collatz


【解决方案1】:

你的循环永远不会结束:你到达j == 1,但你继续申请3n + 1,这会让你回到4,因此你永远处于循环中:

1 -> 4 -> 2 -> 1 -> ...

顺便说一句:

*num++;

没有做你认为它正在做的事情。您正在递增指针,然后访问该值(未使用)。所以就好像你写了:

num++;

你应该写(*num)++

【讨论】:

    【解决方案2】:

    问题出在j = j * 3 + 1;,如果'j' 大于1 且为奇数,'j' 会继续增加。所以它挂在calculate(int j,int *num),因为它内部的while循环无限运行(j值将在一段时间后重置)。

    编辑:

    我已经积累了所有的更正并添加了代码:

    main.c:

    #include "input_output.h"
    #include <stdlib.h>
    
    int main()
    {
            int i=0, j=0;
            int *num,*ori;                  //New pointer required to remember the start position of num
            int maxCycle;
            int length;
            input(&i, &j);
            length = j - i + 1;
            num = (int*)calloc((size_t)(j-i+1),sizeof(int));
            ori=num;
            while (i <= j)
            {
                    calculate(j, num);
                    j--;
                    num++;
            }
            num=ori;
            maxCycle = findMax(length, num);
            num=ori;
            output(maxCycle);
            return 0;
    }
    

    输入输出.h:

    #ifndef INPUT_OUTPUT_H
    #define INPUT_OUTPUT_H
    
    void input(int *i, int *j);
    void calculate(int j,int *num);
    int findMax(int length, int* num);
    void output(int maxout);
    
    #endif
    

    input_output.c:

    #include <stdio.h>
    #include "input_output.h"
    void input(int *i, int *j) {
            printf("Enter the i & j:\n");
            scanf("%d%d",i,j); 
            printf("Values entered:\ni: %d\nj: %d",*i,*j);
    }
    
    void calculate(int j, int* num) {
    
            while (j > 1) {     
                    if (j==1)
                            break;
                    if (j % 2 == 0) {   
                            j = j / 2;
                            (*num)++;         
                    }
                    else{   
                            j = j * 3 + 1;  
                            (*num)++;         
                    }
            }
    
            printf("\nLength Value: %d\n",*num);
    }
    
    int findMax(int length, int * num){
            int max = 0;
            int idx = 0;
            printf("\nLength Values:\n");
            while (idx < length) {
                    printf("%d ",*num);
                    if (*num > max) 
                            max = *num;
                    idx++;
                    num++;
            }
            return max;
    
    }
    
    void output(int maxout) {
            printf("\nResult: %d", maxout);
    }
    

    在 linux 中编译使用:gcc input_output.c main.c -Wall -Wextra -pedantic -Wconversion -std=gnu11 -o collatz

    如需进一步说明,请发表评论。

    【讨论】:

    • 根据Collat​​z猜想,j应该收敛到1。所以我认为while循环不会无限运行,我将“while(i> = 1)”改为“while(i> 0) " 但还是不行。
    • i & j 的值是多少?
    • 在j必须大于i的情况下,它们可以是任何数字排除
    • 试试@Acorn所说的,如果你想将值指针的值增加num,试试(*num)++
    猜你喜欢
    • 1970-01-01
    • 2020-12-30
    • 2017-02-22
    • 2019-05-06
    • 1970-01-01
    • 2020-10-17
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多