C:循环而不使用循环语句或递归

Pra*_*u R 14 c loops

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

qrd*_*rdl 17

#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);
}
Run Code Online (Sandbox Code Playgroud)

我认为它不算递归.

  • @Effo,根据你的推理,任何使用printf()的解决方案也都是无效的,因为它无疑使用某种循环来处理格式字符串.这将使印刷线变得相当困难. (6认同)

Too*_*the 15

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();
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

Kje*_*sen 15

具有阻塞读取,信号和报警功能.我以为我必须使用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);
}
Run Code Online (Sandbox Code Playgroud)

  • 不是标准的C,但我不会投票给你,因为任何奇怪的人都想出这个解决方案,可能是精神病,足以追踪我并造成严重伤害:-) (15认同)

epa*_*tel 13

我会去使用 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;
}
Run Code Online (Sandbox Code Playgroud)


Vad*_*ath 10

您可以通过嵌套宏来完成此操作.

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)
Run Code Online (Sandbox Code Playgroud)

总共将有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 );
}
Run Code Online (Sandbox Code Playgroud)

  • 只需从宏参数中删除N,就可以了.我很确定生成的4GB源文件会杀死编译器,但理论上它应该可以工作. (3认同)

Tec*_*ise 7

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

对于那些对某人有这样的问题感到好奇的人来说,这是印度招聘新鲜毕业生的常见问题之一.

  • 因此,一个标准的招聘问题是"如果不使用任何你应该使用的方法,你如何做一些平凡的事情,而是以一种不必要的拜占庭式和复杂的方式,无缘无故地做到这一点?" 哎呀,怎么适用. (15认同)
  • 允许setjmp/longjmp使一切变得简单.实际上,我会禁止使用任何关键字或任何ASCII字符. (5认同)
  • mrduclaw:术语"语法糖"意味着你可以使用goto实现setjmp/longjmp.你不能.setjmp/longjmp允许非本地跳转. (3认同)
  • 这解释了外包给某些国家如何获得如此糟糕的声誉; 因为产生的代码是垃圾. (3认同)

And*_*eck 5

首先将所有可能的输出写入字符串,并在输出停止的位置将null终止.
这是一个相当肮脏的解决方案,但考虑到这些限制,
除了使用汇编程序之外,我能想到的全部 .

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);}
Run Code Online (Sandbox Code Playgroud)

鉴于MAX_INT==2147483647在流行的架构上,我们只需要去+c(999999999).输入那个初始字符串可能需要一段时间,但是......


小智 5

这样做:

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

这是另一个:

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • 我检测到缓冲区溢出"功能". (3认同)
  • 我已经在你面前发表了这篇评论.干杯...... - :) (2认同)