Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of &ampersand and square bracket in printf

Tags:

c

printf

I came across the following code in an MCQ quiz,

#include <stdio.h>
int main()
{
    int j =2, k =4;
    printf(&j["Programming"], &k["Theory"]);
    k = j ^ 3;
    if (k == j)
        printf(&k["Practical"], "Trytosolve");
    else
        printf(&j["Problem creation"]);
    return 0;
}

where ampersand is used in the beginning itself and outside the quotes ("") of printf statement. I am only aware of the traditional use of printf statement and its format specifiers. I tried to run this code, and it showed no error but this warning: format not a string literal and no format arguments

and the following output

ogrammingoblem creation (this was one of the options in multiple choices)

I tried to search for such use, but could not find. Can someone explain this use of & and square brackets?

like image 664
Prabhanshu Chandra Avatar asked Nov 04 '20 08:11

Prabhanshu Chandra


2 Answers

Because I hate answers in the form of comments I will spell it our here again in a bit more detail:

Say we have an array a and a variable i of integral type, then a[i] is equivalent to *(a + i), i.e. we can obtain the ith element of a by decaying a into a pointer to its first element, incrementing that pointer by i and dereferencing the result. This it true because arrays occupy contiguous addresses in memory.

Now, as it turns out, i[a] is also equivalent to a[i], this is more of a "trick" that nobody (to my knowledge) would ever use in production. It's sort of intuitively justifiable that this would be the case because a[i] == *(a + i) == *(i + a) == i[a].

So then, &j["Programming"] == &(*(j + "Programming")). And because dereferencing a pointer and then taking it's address is a noop, this is j + "Programming" == "Programming" + j == "ogramming", because strings are just arrays of characters.

Same for the other branch, which is executed because 2 ^ 3 == 1 != 2.

like image 51
Peter Avatar answered Sep 29 '22 19:09

Peter


Maybe this example program will show you the math behind the scenes:

#include <stdio.h>
int main(void)
{
    int j=2, k=4;
    char *p1 = "Programming";

    // Print the address of j
    printf("&j = %p\n", &j);
    printf("\n");

    printf("Pointer arithmetic\n");
    // Print the address of "Programming"
    printf("p1                = %p\n", p1);
    // Print the value of j
    printf("j                 = %8d\n", j);
    // Print the result of the pointer computation
    printf("&j[\"%s\"] = %p\n", p1, &j[p1]);
    // Print the result of the equivalent pointer computation
    printf("p1 + j            = %p\n", p1 + j);
    printf("\n");

    printf("Print strings\n");
    // Print "Programming" after skipping the first two letters
    printf("&j[\"%s\"] = %s\n", p1, &j[p1]);
    // Print "Programming" after skipping the first two letters
    printf("p1 + j            = %s\n", p1 + j);
    return 0;
}

Output

&j = 0x7fffb3325aa8

Pointer arithmetic
p1                = 0x4006e4
j                 =        2
&j["Programming"] = 0x4006e6
p1 + j            = 0x4006e6

Print strings
&j["Programming"] = ogramming
p1 + j            = ogramming
like image 34
David Cullen Avatar answered Sep 29 '22 20:09

David Cullen