开发者

C puzzle: Output of printf should be '5' always

开发者 https://www.devze.com 2022-12-19 09:23 出处:网络
I found this puzzle in a C aptitude paper. void change() { //write something in this function so that output of printf in main 开发者_如何学Cfunction

I found this puzzle in a C aptitude paper.

void change()
{
    //write something in this function so that output of printf in main 开发者_如何学Cfunction
    //should always give 5.you can't change the main function
}

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

Any solutions.?


define?

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


This is a POSIX answer that really does what the problem asks :)

It won't work on some architectures/compilers but it does here.

#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: This should make it more robust for people with boycotting headers.


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
}


Here's a really cheap answer:

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

:-P


Here's another possibility:

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

This is much more portable than changing the return address, but requires you to (a) have a compiler that pools string literals (most do), and (b) have a compiler that doesn't place constants in a read-only section, or be running on an architecture with no MMU (unlikely these days).


Anybody thought of using atexit?


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

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

Note that there is no terminating newline in the main function, if we send 2 backspace characters to stdout, the 10 will be erased, and only the 5 will be printed.


Invoke the requisite #include, and replace the comment with the parenthesis-unbalanced text:

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

Tested successfully. Thanks to dreamlax and Chris Lutz for bugfixes.


You have a local variable i in the stack that has a value of 5 to begin with.

With change(), you need to modify the next instruction to be 5 so you would need to buffer override to that location where 10 is set, and have it set to 5.


The printf("%d", i); call in main() doesn't end its output in a newline, the behavior of the program is implementation-defined.

I assert that on my implementation, a program that fails to write a terminating newline for the final line always prints 5 followed by a newline as its last line.

Thus, the output will always be 5, whatever the definition of change(). :-)

(In other words, what's the point of such questions, unless they're meant to run on particular hardware, compiler, etc.?)


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


Simple:

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

Slightly more sophisticated:

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


I suspect that the "correct" answer to this is to modify the return address on the stack within the change() function, so that when it returns the control flow skips the i=10 command and goes straight to the printf.

If so then that is a horrible, ugly question and the (non-portable) answer requires knowledge of the architecture and instruction set used.


How about something like this: (x86 only)

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


Loving the answers in here. I got it to work in two lines.

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

The 10 will never reach the output because after the change() function prints a 5, the stdout file descriptor is closed.

People can verify that using the following online C compiler.

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


here is a different one:

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

do I get the "smallest #define to solve a silly problem award"?


I am not sure this would always work, but what about locating the i variable on the stack like this:

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

精彩评论

暂无评论...
验证码 换一张
取 消