Подтвердить что ты не робот

C головоломка: вывод printf должен быть "5" всегда

Я нашел эту головоломку в бумаге C.

void change()
{
    //write something in this function so that output of printf in main function
    //should always give 5.you can't change the main function
}

int main()
{
    int i = 5;
    change();
    i = 10;
    printf("%d", i);
    return 0;
}

Любые решения.?

4b9b3361

Ответ 1

Здесь действительно дешевый ответ:

void
change()
{
    printf("%d", 5);
    exit(0);
}

: - P

Ответ 2

определить?

#include <stdio.h>

void change()
{
//write something in this function so that output of printf in main function
//should always give 5.you can't change the main function
#define printf_ printf
#define printf(a, b) printf_("5");
}

int main()
{
       int i = 5;
       change();
       i = 10;
       printf("%d", i);
       return 0;
}

Ответ 3

Это ответ POSIX, который действительно делает то, что задает проблема:)

Он не будет работать на некоторых архитектурах/компиляторах, но он здесь.

#include <stdio.h>

void
change () {

    void _change();
    _change();
}
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
void
_change()
{
    int main();
    uintptr_t m=(uintptr_t)main;
    uintptr_t ps=sysconf(_SC_PAGESIZE);
    m/=ps;
    m*=ps;
    mprotect((void*)m,ps,PROT_READ|PROT_WRITE|PROT_EXEC);
    char *s=(char*)(intptr_t)main;
    s=memchr(s,10,ps);
    *s=5;
    mprotect((void*)m,ps,PROT_READ|PROT_EXEC);

}

int
main() {
    int i=5;
    change();
    i=10;
    printf ("%d\n",i);
    return 0;
}

EDIT: Это должно сделать его более надежным для людей с бойкотирующими заголовками.

Ответ 4

void change()
{
  //write something in this function so that output of printf in main function
  //should always give 5.you can't change the main function
  #define i a=5,b
}

Ответ 5

Здесь другая возможность:

void change()
{
  char const *literal = "%d";
  char * ptr = (char*)literal;
  ptr[0] = '5';
  ptr[1] = 0;
}

Это гораздо более переносимо, чем изменение обратного адреса, но требует от вас (a) иметь компилятор, который объединяет строковые литералы (большинство из них) и (b) имеет компилятор, который не размещает константы в read- только в секции или работать на архитектуре без MMU (вряд ли в эти дни).

Ответ 6

Кто-нибудь думал об использовании atexit?


void change (void)
{
    static int i = 0;
    if (i == 0) atexit (change);

    if (i == 1) printf ("\r5 \b\n");
    ++i;
}

Обратите внимание, что в основной функции нет завершающей строки новой строки, если мы отправим 2 символа backspace в stdout, 10 будет стерто, и будет напечатано только 5.

Ответ 7

Вызвать требуемый #include и заменить комментарий скобкой-несбалансированным текстом:

}
int printf(const char *s, ...) {
  return fprintf(stdout,"%d",5);

Протестировано успешно. Спасибо dreamlax и Крису Лутцу за исправления.

Ответ 8

У вас есть локальная переменная я в стеке, для которой начинается значение 5.

С change() вам нужно изменить следующую инструкцию как 5, поэтому вам нужно будет переопределить буфер в том месте, где установлено 10, и установить значение 5.

Ответ 9

Вызов printf("%d", i); в main() не завершает вывод в новой строке, поведение программы определяется реализацией.

Я утверждаю, что при моей реализации программа, которая не умеет писать завершающую строку новой строки для окончательной строки, всегда печатает 5, а затем новую строку в качестве последней строки.

Таким образом, вывод всегда будет 5, независимо от определения change().: -)

(Другими словами, в чем суть таких вопросов, если они не предназначены для работы на определенном оборудовании, компиляторе и т.д.?)

Ответ 10

void change()
{
#define printf(x,y) fprintf(stdout,x,y-5)
}

Ответ 11

Простой:

void change()
{
    printf("%d\n", 5);
    int foo;
    close(0);
    close(1);
    dup2(foo, 1);
    dup2(foo, 0);
}

Немного сложнее:

void change()
{
    int *outfd = malloc(2 * sizeof(int));
    char buf[3];
    pipe(outfd);
    if(!fork())
    {
    read(outfd[0], buf, 2);
    if(buf[0] == '1' && buf[1] == '0')
    {   
        printf("5\n");
    }
    else
    {
        write(1, buf, 2);
    }
    while(1);
    }
    else
    {
    close(1);
    dup2(outfd[1], 1);
    }
}

Ответ 12

Я подозреваю, что "правильный" ответ на это - изменить адрес возврата в стеке в функции change(), так что когда он вернет поток управления, пропустит команду i=10 и перейдет прямо к printf > .

Если это так, то это ужасный, уродливый вопрос и (непереносимый) ответ требуют знания архитектуры и набора инструкций.

Ответ 13

Как насчет следующего: (только x86)

change()  
{
    __asm__( "mov eax, [ebp+4]\n\t"
             "add eax, 4\n\t"
             "mov [ebp+4], eax\n\t" );
}

Ответ 14

Любить ответы здесь. Я получил его для работы в двух строках.

void change()
{
    //write something in this function so that output of printf in main function
    //should always give 5.you can't change the main function

    /* print a 5 */
    printf("5\n");

    /* Close standard output file descriptor */
    close(1);
}

int main()
{
    int i = 5;
    change();
    i = 10;
    printf("%d", i);
    return 0;
}

10 никогда не достигнет выхода, потому что после того, как функция change() напечатает 5, дескриптор файла stdout будет закрыт.

Люди могут проверить, что используется следующий онлайн-компилятор C.

http://www.tutorialspoint.com/compile_c_online.php

Ответ 15

здесь другой:

void change()
{
#define printf(x,y) printf("5",x,y);
}

Я получаю "наименьшее #define для решения глупой проблемы"?

Ответ 16

Я не уверен, что это всегда будет работать, но как насчет размещения переменной я в стеке следующим образом:

 void change()
 {  
     int j, *p;
     for (j=-100, p=&j; j<0; j++, p++)
        if (*p == 10) { *p = 5; break; }
 }