Загадка C: вывод printf всегда должен быть равен 5 - PullRequest
18 голосов
/ 02 февраля 2010

Я нашел эту загадку в газете способностей.

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

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

Ответы [ 16 ]

27 голосов
/ 04 февраля 2010

Это ответ 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;
}

РЕДАКТИРОВАТЬ: Это должно сделать его более устойчивым для людей с бойкотирующими заголовками.

27 голосов
/ 02 февраля 2010

определить

#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;
}
25 голосов
/ 02 февраля 2010
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
}
21 голосов
/ 02 февраля 2010

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

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

: - P

20 голосов
/ 02 февраля 2010

Вот еще одна возможность:

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

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

9 голосов
/ 28 марта 2010

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


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

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

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

8 голосов
/ 02 февраля 2010

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

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

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

6 голосов
/ 02 февраля 2010

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

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

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

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

6 голосов
/ 02 февраля 2010

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

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

4 голосов
/ 02 февраля 2010

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

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

...