【问题标题】:C: Looping without using looping statements or recursionC:不使用循环语句或递归的循环
【发布时间】:2010-12-06 14:27:48
【问题描述】:

我想编写一个 C 函数,它将在标准输出上的每一行打印 1 到 N 个,其中 N 是函数的 int 参数。该函数不应使用 while、for、do-while 循环、goto 语句、递归和 switch 语句。有可能吗?

【问题讨论】:

  • 如果这是一个挑战问题,我们给你一个答案,挑战将被破坏。
  • printf("1 到 N");
  • 也许可以使用宏?
  • system(("MyExe %d",N-1)) 算作递归吗? :P
  • 使用内联汇编,大功告成。

标签: c loops


【解决方案1】:
#include <stdlib.h>

int callback(const void *a, const void *b) {
    static int n = 1;

    if (n <= N)
        printf("%d\n", n++);

    return 0;
}

int main(int argc, char *argv) {
    char *buf;
    /* get N value here */

    buf = malloc(N);  // could be less than N, but N is definitely sufficient
    qsort(buf, N, 1, callback);
}

我认为这不算递归。

【讨论】:

  • qsort 在内部使用“for”或“while”,所以你的想法违反了规则。
  • @Effo,根据您的推理,任何使用 printf() 的解决方案也是无效的,因为它无疑使用了某种循环来处理格式字符串。这将使打印线变得非常困难。
  • 很难吗?来吧,什么是挑战?
【解决方案2】:

具有阻塞读取、信号和警报功能。我以为我必须使用 sigaction 和 SA_RESTART,但没有它似乎也能很好地工作。

请注意,setitimer/alarm 可能是 unix/-like 特定的。

#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

volatile sig_atomic_t counter;
volatile sig_atomic_t stop;

void alarm_handler(int signal)
{
  printf("%d\n", counter++);
  if ( counter > stop )
  {
    exit(0);
  }
}

int main(int argc, char **argv)
{
  struct itimerval v;
  v.it_value.tv_sec = 0;
  v.it_value.tv_usec = 5000;
  v.it_interval.tv_sec = 0;
  v.it_interval.tv_usec = 5000;
  int pipefds[2];
  char b;

  stop = 10;
  counter = 1;

  pipe(pipefds);

  signal(SIGALRM, alarm_handler);

  setitimer(ITIMER_REAL, &v, NULL);

  read(pipefds[0], &b, 1);
}

【讨论】:

  • 不是标准的 C,但我不会投票给你,因为任何奇怪到想出这个解决方案的人都可能精神错乱,足以追踪我并造成严重伤害 :-)
  • @paxdiablo:是的,害怕我的书呆子体质!此外,雪上加霜的是,C99 指出在信号处理程序中调用即 printf 可能没有完全定义。 :)
【解决方案3】:

N 不是固定的,所以你不能解除循环。据我所知,C 没有迭代器。

你应该找到一些模仿循环的东西。

或跳出框框思考:

(比如N限制在1000,但是很容易适应)

int f(int N) {
    if (N >= 900) f100(100);
    if (N >= 800) f100(100);
    if (N >= 700) f100(100);
    ...

    f100(n % 100);
}

int f100(int N) {
    if (N >= 90) f10(10);
    if (N >= 80) f10(10);
    if (N >= 70) f10(10);
    ...

    f(n % 10);
}

int f10(int N) {
    if (N >= 9) func();
    if (N >= 8) func();
    if (N >= 7) func();
    ...
}

【讨论】:

  • 这似乎是迄今为止最好的解决方案,每个新的功能级别都会让您的空间增加十倍。这应该会让你很快达到 2^63-1。
  • 可以用宏包起来
  • +1。所有其他解决方案都使用标准库中的某些类似于 goto 或循环的东西(longjmp、信号队列、atexit 堆栈、qsort 中的循环)。这甚至不会出现在库中(除了需要添加以完成代码的实际 I/O 代码),因此作为一种解决方案,它对于简单的需求更改是健壮的。
【解决方案4】:

我会选择使用longjmp()

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

void do_loop(int n) {
  int val;
  jmp_buf env;

  val = 0;

  setjmp(env);

  printf("%d\n", ++val);

  if (val != n)
    longjmp(env, 0);  
}

int main() {
  do_loop(7);
  return 0;
}

【讨论】:

  • 不错,使用 setjmp/longjmp 模拟 goto。大多数whippersnappers甚至不知道这些功能的存在:-) +1。
  • 这让我大吃一惊。太棒了。
【解决方案5】:

您可以通过嵌套宏来做到这一点。

int i = 1;

#define PRINT_1(N) if( i < N ) printf("%d\n", i++ );
#define PRINT_2(N) PRINT_1(N) PRINT_1(N)
#define PRINT_3(N) PRINT_2(N) PRINT_2(N)
#define PRINT_4(N) PRINT_3(N) PRINT_3(N)
:
:
#define PRINT_32(N) PRINT_31(N) PRINT_31(N)

总共将有 32 个宏。假设int 的大小为 4 个字节。现在从任何函数调用PRINT_32(N)

编辑: 为了清楚起见,添加示例。

void Foo( int n )
{
    i = 1;

    PRINT_32( n );
}


void main()
{
    Foo( 5 );
    Foo( 55 );
    Foo( 555 );
    Foo( 5555 );
}

【讨论】:

  • 只需从宏参数中删除 N 即可。我很确定生成的 4GB 源文件会杀死编译器,但理论上它应该可以工作。
  • 它会大于 4GB,不是吗? 2^32 *(28 字节)= 120GB。
  • 谢谢大家;我知道这个想法不切实际,但它是合乎逻辑的......我不认为有一个编译器有足够的堆来编译这段代码。这可能是应该在 2050 年之前完成的代码 -:)
【解决方案6】:

您可以使用 setjmp 和 logjmp 函数来执行此操作,如图所示 in this C FAQ

对于那些想知道为什么有人会提出这样的问题的人,这是印度招聘应届毕业生的常见问题之一。

【讨论】:

  • 所以一个标准的招聘问题是“你如何在不使用任何你应该使用的方法的情况下做一些平凡的事情,而不是毫无理由地以一种不必要的拜占庭式和复杂的方式去做?”哎呀,多么适用。
  • 是的,这是一个“标准”招聘问题。但大多数提出此类问题的公司实际上并没有招聘他们从事 C 程序员的工作,而且在大多数情况下,提出此类问题的人并没有真正的编程经验。
  • mrduclaw:术语“语法糖”意味着您可以使用 goto 实现 setjmp/longjmp。你不能。 setjmp/longjmp 允许非本地跳转。
  • 允许 setjmp/longjmp 让一切变得太容易了。实际上,我完全禁止使用任何关键字或任何 ASCII 字符。
  • 这解释了外包给某些国家是如何获得如此糟糕的声誉的;因为生成的代码是垃圾。
【解决方案7】:

首先将所有可能的输出写入一个字符串,然后在输出应该停止的地方终止它。
这是一个相当肮脏的解决方案,但鉴于限制,我能想到的,
当然,除了使用汇编程序。

char a[]="1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n"/*...*/;
main(n,v)char**v;{n=atoi(v[1]);
#define c(x)(n>x?n-x:0)
a[n+c(1)+c(9)+c(99)+c(999)+c(9999)+c(99999)+c(999999)+c(9999999)/*+...*/]=0;
puts(a);}

鉴于MAX_INT==2147483647 在流行架构上,我们只需要升级到+c(999999999)。不过,输入初始字符串可能需要一段时间...

【讨论】:

    【解决方案8】:

    你没有禁止fork()

    【讨论】:

    • 但这几乎肯定会被视为递归。
    【解决方案9】:

    如果你知道 N 的上限,你可以试试这样的方法;)

    void func(int N)
    {
        char *data = " 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n";
        if (N > 0 && N < 12)
            printf("%.*s", N*3, data);
        else
            printf("Not enough data. Need to reticulate some more splines\n");
    }
    

    开个玩笑,我真的不明白如果没有递归或你在那里提到的所有指令,你怎么能做到这一点。这让我对解决方案更加好奇。

    编辑:刚刚注意到我提出了与 grombeestje 相同的解决方案 :)

    【讨论】:

      【解决方案10】:

      这样做:

      int main ()
      {
      printf ("1 to N one per each line\n");
      return 0;
      }
      

      这是另一个:

      #include <stdlib.h>
      #include <stdio.h>
      
      int main (int c, char ** v) {
          char b[100];
          sprintf (b, "perl -e 'map {print \"$_\\n\"} (1..%s)'", v[1]);
          system (b);
          return 0;
      }
      

      【讨论】:

      • 我已经在你面前发表了这篇评论。干杯.. -:)
      • 哦,对不起,我没注意到。
      • 我检测到缓冲区溢出“功能”。
      【解决方案11】:

      另一件事(在 linux 上)将按照以下方式执行,其中 7 是 N

      int main() {
          return system("seq 7");
      }
      

      【讨论】:

        【解决方案12】:

        这会从命令行获取整数 N 并从 1 打印到 N

        #include <stdio.h>
        #include <stdlib.h>
        
        int total;
        int N;
        
        int print16(int n)
        {
            printf("%d\n",n+0x01); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x02); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x03); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x04); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x05); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x06); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x07); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x08); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x09); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x0A); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x0B); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x0C); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x0D); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x0E); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x0F); total++; if (total >= N) exit(0);
            printf("%d\n",n+0x10); total++; if (total >= N) exit(0);
        }
        
        int print256(int n)
        {
            print16(n);
            print16(n+0x10);
            print16(n+0x20);
            print16(n+0x30);
            print16(n+0x40);
            print16(n+0x50);
            print16(n+0x60);
            print16(n+0x70);
            print16(n+0x80);
            print16(n+0x90);
            print16(n+0xA0);
            print16(n+0xB0);
            print16(n+0xC0);
            print16(n+0xD0);
            print16(n+0xE0);
            print16(n+0xF0);
        }
        
        int print4096(int n)
        {
            print256(n);
            print256(n+0x100);
            print256(n+0x200);
            print256(n+0x300);
            print256(n+0x400);
            print256(n+0x500);
            print256(n+0x600);
            print256(n+0x700);
            print256(n+0x800);
            print256(n+0x900);
            print256(n+0xA00);
            print256(n+0xB00);
            print256(n+0xC00);
            print256(n+0xD00);
            print256(n+0xE00);
            print256(n+0xF00);
        }
        
        int print65536(int n)
        {
            print4096(n);
            print4096(n+0x1000);
            print4096(n+0x2000);
            print4096(n+0x3000);
            print4096(n+0x4000);
            print4096(n+0x5000);
            print4096(n+0x6000);
            print4096(n+0x7000);
            print4096(n+0x8000);
            print4096(n+0x9000);
            print4096(n+0xA000);
            print4096(n+0xB000);
            print4096(n+0xC000);
            print4096(n+0xD000);
            print4096(n+0xE000);
            print4096(n+0xF000);
        }
        
        int print1048576(int n)
        {
            print65536(n);
            print65536(n+0x10000);
            print65536(n+0x20000);
            print65536(n+0x30000);
            print65536(n+0x40000);
            print65536(n+0x50000);
            print65536(n+0x60000);
            print65536(n+0x70000);
            print65536(n+0x80000);
            print65536(n+0x90000);
            print65536(n+0xA0000);
            print65536(n+0xB0000);
            print65536(n+0xC0000);
            print65536(n+0xD0000);
            print65536(n+0xE0000);
            print65536(n+0xF0000);
        }
        
        int print16777216(int n)
        {
            print1048576(n);
            print1048576(n+0x100000);
            print1048576(n+0x200000);
            print1048576(n+0x300000);
            print1048576(n+0x400000);
            print1048576(n+0x500000);
            print1048576(n+0x600000);
            print1048576(n+0x700000);
            print1048576(n+0x800000);
            print1048576(n+0x900000);
            print1048576(n+0xA00000);
            print1048576(n+0xB00000);
            print1048576(n+0xC00000);
            print1048576(n+0xD00000);
            print1048576(n+0xE00000);
            print1048576(n+0xF00000);
        }
        
        int print268435456(int n)
        {
            print16777216(n);
            print16777216(n+0x1000000);
            print16777216(n+0x2000000);
            print16777216(n+0x3000000);
            print16777216(n+0x4000000);
            print16777216(n+0x5000000);
            print16777216(n+0x6000000);
            print16777216(n+0x7000000);
            print16777216(n+0x8000000);
            print16777216(n+0x9000000);
            print16777216(n+0xA000000);
            print16777216(n+0xB000000);
            print16777216(n+0xC000000);
            print16777216(n+0xD000000);
            print16777216(n+0xE000000);
            print16777216(n+0xF000000);
        }
        
        int print2147483648(int n)
        {
           /*
            * Only goes up to n+0x70000000 since we
            * deal only with postive 32 bit integers
            */
           print268435456(n);
           print268435456(n+0x10000000);
           print268435456(n+0x20000000);
           print268435456(n+0x30000000);
           print268435456(n+0x40000000);
           print268435456(n+0x50000000);
           print268435456(n+0x60000000);
           print268435456(n+0x70000000);
        }
        
        
        int main(int argc, char *argv[])
        {
           int i;
        
           if (argc > 1) {
              N = strtol(argv[1], NULL, 0);
           }
        
           if (N >=1) {
              printf("listing 1 to %d\n",N);
              print2147483648(0);
           }
           else {
              printf("Must enter a postive integer N\n");
           }
        }
        

        【讨论】:

          【解决方案13】:
          int x=1;
          
          void PRINT_2(int);
          
          void PRINT_1(int n)
          { if(x>n)
              return;
            printf("%d\n",x++);
            PRINT_2(n);  
          }
          
          void PRINT_2(int n)
          { if(x>n)
              return;
            printf("%d\n",x++);
            PRINT_1(n);  
          }
          
          int main() 
          {   int n;
              scanf("%d",&n);
              if(n>0)
                PRINT_1(n);
              system("pause");
          }
          

          【讨论】:

            【解决方案14】:
             #include "stdio.h"
            
             #include "stdlib.h"
            
             #include "signal.h"
            
             int g_num;
            
             int iterator;
            
             void signal_print()
            
             {
            
                    if(iterator>g_num-1)
            
                            exit(0);
            
                    printf("%d\n",++iterator);
            
             }
            
             void myprintf(int n)
            
             {
            
                 g_num=n;
            
                    int *p=NULL;
            
                 int x= *(p); // the instruction is reexecuted after handling the signal
            
             }
            
             int main()
            
             {
            
                    signal(SIGSEGV,signal_print);
            
                    int n;
            
                    scanf("%d",&n);
            
                    myprintf(n);
            
                    return 0;
            
             }
            

            【讨论】:

              【解决方案15】:

              我对这不起作用感到非常失望。对我来说,短语“在注册时已经调用的任何先前注册的函数之后调用函数”表明可以在开始调用 atexit 处理程序之后注册它们。也就是说,一个处理程序可以注册另一个处理程序。否则,怎么可能存在一个在注册另一个函数时已被调用的函数?但对我来说,对 atexit 的调用返回 0 成功,但实际上并没有导致另一个调用。任何人都知道为什么,我犯了一些愚蠢的错误吗?

              #include "stdio.h"
              #include "stdlib.h"
              
              int count = 0;
              int limit = 10;
              
              void handler() {
                  printf("%d of %d\n", ++count, limit);
                  if (count < limit) atexit(handler);
              }
              
              int main(int argc, char **argv) {
                  if (argc > 1) limit = atoi(argv[1]);
                  atexit(handler);
              }
              

              顺便说一句,不是递归,因为 atexit 不调用它的参数,它会将它排队等待稍后调用。显然,C 运行时包含一个调用 atexit 处理程序的循环,但无论您是否实际注册任何 atexit 处理程序,该循环都存在。因此,如果这个程序包含一个循环,那么每个 C 程序也是如此;-)

              【讨论】:

              • 请参阅“现代 C++ 设计:应用通用编程和设计模式”第 6.6.1 节 atexit 的问题。
              • 谢谢。总结:标准不充分,并没有具体说明应该发生什么。该标准已更正。我的编译器没有包含更正,但如果它包含了,那么这段代码就可以工作。
              • 也许你的代码被否决是因为它不能编译,而不是因为它使用了 atexit。
              【解决方案16】:
                  /// <summary>
                  /// Print one to Hundred without using any loop/condition.
                  /// </summary>
                  int count = 100;
                  public void PrintOneToHundred()
                  {
                      try
                      {
                          int[] hey = new int[count];
                          Console.WriteLine(hey.Length);
                          count--;
                          PrintOneToHundred();
                      }
                      catch
                      {
                          Console.WriteLine("Done Printing");
                      }
                  }
              

              【讨论】:

              • 他也不允许使用递归
              • 另外,为什么要创建一个新数组[count] 并打印长度,为什么不直接打印 count 并完全跳过数组?
              猜你喜欢
              • 2023-03-24
              • 2011-08-11
              • 1970-01-01
              • 2021-03-20
              • 2012-11-01
              • 2017-09-28
              • 2012-08-01
              • 2021-06-17
              • 2018-08-05
              相关资源
              最近更新 更多