2009-10-14 3 views
13

Я хочу написать функцию C, которая будет печатать от 1 до N по одной на каждую строку на stdout, где N является параметром int для функции. Функция не должна использоваться во время циклов do-while, инструкции goto, рекурсии и оператора switch. Является ли это возможным?C: Looping без использования инструкций цикла или рекурсии

+4

из curiosi Почему? – phoebus

+13

Если это сложный вопрос, и мы даем вам ответ, проблема будет испорчена. –

+0

разрешено использовать инструкции сборки в c-коде? –

ответ

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); 
} 
+15

Не стандарт C, но я не буду проголосовать за вас, так как любой причудливый достаточно, чтобы придумать это решение, вероятно, достаточно психотичен, чтобы отследить меня и нанести серьезный вред :-) – paxdiablo

+1

@paxdiablo: да, боюсь, тело моего ботаника! Кроме того, добавление оскорбления к травме, C99 заявляет, что вызов, т. Е. Printf внутри обработчика сигналов, может быть не полностью определен. :) –

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);} 

Учитывая, что MAX_INT==2147483647 на популярных архитектур, нам нужно только подойти к +c(999999999). Вывод этой начальной строки может занять некоторое время, хотя ...

+1

Код или этого не произошло! – spoulson

+0

Там я исправил его. – ephemient

4

Вы не запретили fork().

+6

Но это почти наверняка будет считаться рекурсией. – paxdiablo

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(); 
    ... 
} 
+2

Yhis кажется лучшим решением на сегодняшний день, каждый новый уровень функции дает вам десятикратное увеличение пространства. Это должно привести вас к 2^63-1 довольно быстро. – paxdiablo

+3

Можно обернуть его в макросы – vava

+2

+1. Все остальные решения используют что-то в стандартных библиотеках, которые в некотором роде похожи на ходоподобные или похожие на петли (longjmp, очередь сигналов, стек atexit, цикл в qsort). Это даже не доходит до библиотек (за исключением фактического кода ввода-вывода, который необходимо добавить для завершения кода), так как решение устойчиво к простым изменениям требований. –

4

Если вы знаете, верхний предел 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 :)

5

Это делает:

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; 
} 
+2

Я уже разместил это как комментарий перед вами. Cheers .. - :) – Vadakkumpadath

+1

О, извините, но я этого не заметил. – 2009-10-14 08:58:05

+3

Я обнаружил функцию переполнения буфера. – spoulson

7

Вы можете используйте функции setjmp и logjmp для этого, как показано на рисунке in this C FAQ

Для тех, кому интересно, почему у кого-то есть такой вопрос, это один из часто задаваемых вопросов в Индии для найма свежих сортов.

+15

Итак, стандартный вопрос вербовки: «Как вы делаете что-то мирское, не используя какие-либо методы, которые вы должны использовать, а вместо этого делаете это излишне византийским и сложным образом, без всякой причины?» Дай, как это применимо. – phoebus

+1

Да, это своего рода «стандартный» вопрос вербовки здесь. Но большинство компаний, которые задают такие вопросы, даже не набирают их на работу программиста C, и в большинстве случаев человек, задающий такой вопрос, не имеет реального опыта программирования. – Technowise

+1

Является ли setjmp/longjmp просто синтаксическим сахаром для goto? Кажется, как рекрутер, я бы запретил использовать это тоже. – mrduclaw

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) 

Всего будет 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); 
} 
+3

Просто удалите N из параметров макроса, и вы хорошо пойдете. Я уверен, что полученный 4GB исходный файл убьет компилятор, но теоретически он должен работать. – itsadok

+0

Это будет больше 4 ГБ, нет? 2^32 * (28 байтов) = 120 ГБ. –

+0

Спасибо всем; Я знаю, что эта идея непрактична, но это логично ... Я не думаю, что есть компилятор, у которого достаточно кучи для компиляции этого кода. Это может быть код, который должен быть сделан к 2050 году. :) – Vadakkumpadath

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; 
} 
+1

Хороший, эмулирующий goto с setjmp/longjmp. Большинство whippersnappers даже не знают, что эти функции существуют :-) +1. – paxdiablo

+0

Это сбило меня с ног. Потрясающие. – darxsys

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); 
} 

Я думаю, что это не считается рекурсии.

+1

ничего себе. что взорвало мой разум. sneaky: использовать чей-то петлю ... –

+0

qsort использовать «для» или «пока» внутри, поэтому ваша идея нарушает правило. – Test

+6

@Effo, по вашим рассуждениям, любое решение, использующее printf(), также недействительно, поскольку оно, без сомнения, использовало какой-либо цикл для обработки строки формата. Это очень упростит печать строки. – paxdiablo

0

Я очень разочарован тем, что это не работает. Для меня фраза «функция вызывается после того, как какие-либо ранее зарегистрированные функции, которые уже были вызваны в момент ее регистрации», предполагает, что после того, как они начали вызываться, можно зарегистрировать обработчики 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 или нет. Таким образом, если эта программа содержит цикл, так что делает каждую С программой ;-)

+0

см. «Современный дизайн C++: общие шаблоны программирования и дизайна». 6.6.1 Проблемы с atexit. – Test

+0

Кстати, мое предложение atexit получило голос -2, перестаньте его пытаться – Test

+0

Спасибо за это. Резюме: стандарт был неадекватным и не указывал, что должно произойти. Стандарт был скорректирован. Мой компилятор не включает исправление, но если бы это произошло, этот код работал бы. –

1

Это принимает целое число 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"); 
    } 
} 
2

другой штуковины (на Linux) будет будет делать, как показано ниже, где 7 Н

int main() { 
    return system("seq 7"); 
} 
-1
/// <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"); 
     } 
    } 
+0

Он также не может использовать рекурсию. – MattDavey

+0

Кроме того, зачем создавать новый массив [count] и печатать длину, почему бы просто не напечатать счетчик и вообще не пропустить массив? – MattDavey

1
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"); 
} 
1
#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; 

} 
Смежные вопросы