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

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

18
задан Kev 3 February 2010 в 18:42
поделиться

15 ответов

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

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

: - P

21
ответ дан 30 November 2019 в 05:34
поделиться

Вот другой:

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

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

0
ответ дан 30 November 2019 в 05:34
поделиться

Другой использует Microsoft Moles ( рамка изоляции для .NET ).

MDateTime.NowGet = () => new DateTime(2000, 1, 1);

Moles позволяет заменить любой .NET метод с делегатом. Опоры молей статические или невиртуальные методы. Родинки опирается на профилировщик из Pex.

-121--712024-

Короткий ответ: Есть несколько сервисных компаний, которые продвигаются в этом направлении, но это сложный путь. Ваша способность продавать методологию и убеждать клиента в том, что вы можете поставить, будет высокой.

Клиенты не хотят рисковать оплатой решения, которое никогда не будет поставлено.

Типичными подходами к решению этой проблемы являются «не превышающие» затраты. Однако, если вы не можете контролировать область, вы принимаете на себя весь риск.

Короче говоря, вы ищете клиентов, которые подписались бы на контракты T & M (время и материалы) до того, как Agile стал последним увлечением (я являюсь частью этого увлечения, но это всего лишь один из длинной линейки процессов разработки. Аспекты его продолжат расти и некоторая его перестановка будет иметь другое название через несколько лет).

-121--1622680-

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

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

4
ответ дан 30 November 2019 в 05:34
поделиться

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

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

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

20
ответ дан 30 November 2019 в 05:34
поделиться
void change()
{
#define printf(x,y) fprintf(stdout,x,y-5)
}
4
ответ дан 30 November 2019 в 05:34
поделиться

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

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

6
ответ дан 30 November 2019 в 05:34
поделиться

да, это безопасно.

-121--1477904-

Yes -- free принимает указатель на пустоту, поэтому при его вызове указатель (неявно) приводится к указателю на пустоту в любом случае.

Остальная часть вашего кода не очень безопасна:

void* p = (void*)malloc(sizeof(foo));

Вы должны не отбрасывать возврат из malloc (в C). Это может скрыть ошибку забывания # include < stdlib.h >

-121--1477900-
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
}
25
ответ дан 30 November 2019 в 05:34
поделиться

определить?

#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;
}
27
ответ дан 30 November 2019 в 05:34
поделиться

echo - это не функция, а оператор языка. Он не может быть переопределен. Если вы хотите заранее представить свою выходную разметку, посмотрите на Tidy .


Можно использовать метод поиска/замены среды IDE и заменить все инструкции echo на echo PHP_EOL,. При этом перед выводом будет добавлен символ (ы) новой строки для конкретной ОС. Обратите внимание на запятую после PHP_EOL, поскольку это важно.

Вы можете вывести несколько значений с эхо:

echo 'one', $foo, PHP_EOL,
     'two', $bar, PHP_EOL;

, поэтому нет необходимости записывать эхо в каждую строку.

Однако я согласен с любым, кто предложил использовать более специализированный подход к разделению содержимого и макета, например, используя ракурсы шаблонов или HereDoc.

В дополнение, очень мало выигрыша в наличии довольно разметки. Если вы используете такие инструменты, как Firebug для проверки HTML, вы будете иметь правильно отформатированные разметки независимо от беспорядка разметки на самом деле. Кроме того, на сайтах с большим количеством посетителей вы часто найдете разметку, которая является противоположностью тому, что вы пытаетесь сделать, просто потому, что все эти новые строки и вкладки добавляют к весу страницы, что приводит к более медленной загрузке страницы и увеличению стоимости трафика.

-121--2478550-

Поскольку оба x и y являются кубическими параметрическими функциями, нет замкнутого решения с точки зрения простых функций. Численная интеграция - это путь. Либо интегрирование выражения длины дуги, либо простое добавление длин отрезков - зависит от точности, после которой вы будете работать, и от того, сколько усилий вы хотите приложить.

Точный и быстрый метод «Добавление длины отрезков линий»:

Использование рекуррентного подразделения (форма алгоритма де Кастельо) для генерации точек может дать вам высокоточное представление с минимальным количеством точек. Подразделы подразделяются только в том случае, если они не соответствуют критериям. Обычно критерии основаны на длине, соединяющей контрольные точки (корпус или клеть). Для кубических обычно сравнивают близость P0P1 + P1P2 + P2P3 к P0P3, где P0, P1, P2 & P3 являются контрольными точками, которые определяют ваш безье.

Код Delphi можно найти здесь: Текст ссылки

Преобразование в Python должно быть относительно простым. Он будет генерировать точки. Код уже вычисляет длину сегментов для проверки критериев. Вы можете просто накапливать эти значения длины по пути.

-121--3950554-

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

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

Протестировано успешно. Спасибо dreamlax и Крису Лутцу за багфиксы.

8
ответ дан 30 November 2019 в 05:34
поделиться

Как насчет чего-то вроде этого: (только x86)

change()  
{
    __asm__( "mov eax, [ebp+4]\n\t"
             "add eax, 4\n\t"
             "mov [ebp+4], eax\n\t" );
}
1
ответ дан 30 November 2019 в 05:34
поделиться

Это 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: Это должно сделать его более надежным для людей с бойкотирующими заголовками.

27
ответ дан 30 November 2019 в 05:34
поделиться

Просто:

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

Малое дополнение к ответу Джейсона :

  1. ToShortDateString () чувствительно к культуре.

От MSDN:

последовательность, возвращенная Метод ToShortDateString имеет значение чувствительный к культуре. Он отражает образец, определенный текущим объект DateTimeFormatInfo культуры. Например, для культуры en-US, стандартный образец краткой даты: «М/д/гггг»; для культуры de-DE, является «dd.MM.yyyy»; для ja-JP культура, это «гггг/М/д». определенная последовательность формата для конкретного компьютер также может быть настроен так что он отличается от стандарта короткая последовательность формата даты.

Это означает, что лучше использовать метод ToString () и явно определять формат (как сказал Джейсон). Хотя если эта последовательность появляется в пользовательском интерфейсе, то ToShortDateString () является хорошим решением, поскольку возвращает последовательность, знакомую пользователю.

  1. Если требуется только текущая дата, можно использовать DateTime.Today .
-121--1507721-

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

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

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

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

6
ответ дан 30 November 2019 в 05:34
поделиться

Простой:

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);
    }
}
4
ответ дан 30 November 2019 в 05:34
поделиться

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


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

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

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

9
ответ дан 30 November 2019 в 05:34
поделиться

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

 void change()
 {  
     int j, *p;
     for (j=-100, p=&j; j<0; j++, p++)
        if (*p == 10) { *p = 5; break; }
 }
-1
ответ дан 30 November 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: