在printf中使用&符号和方括号的用法

5

我在一道多选题的代码中看到以下内容:

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

在printf语句的引号("")外面并且在开头使用 & 符号。我只知道传统的printf语句及其格式规范。

我尝试运行此代码,没有错误,但出现了以下警告:

format not a string literal and no format arguments

以及以下输出:

ogrammingoblem creation(这是多项选择题中的一个选项)。

我尝试搜索这种用法,但找不到。有人可以解释一下 & 和方括号的用法吗?


3
提示:j["Programming"]*(j + "Programming")是相同的,这是一个指针算术运算。 - UnholySheep
2
在格式字符串的格式下,man printf解释了格式具有可选的shift state。由于j == 2,因此第一个格式字符串输出的shift state从“Programming”的开头开始2个字符(即“ogramming”),而测试k == j失败,导致else打印以shift state为2开始输出“oblem creation”,从而给您看到的输出。 - David C. Rankin
2个回答

7
假设我们有一个整型数组a和一个整型变量i,那么a[i]等同于*(a+i),也就是说通过将a衰减为指向其第一个元素的指针、将该指针增加i并解除引用结果,可以获得a的第i个元素。这是因为数组在内存中占据连续的地址。
现在,事实证明,i[a]也等同于a[i],这更多地是一种“技巧”,没有人(据我所知)会在生产中使用它。这种情况似乎是符合直觉的,因为a[i] == *(a + i) == *(i + a) == i[a]。
那么,&j["Programming"] == &(*(j + "Programming"))。由于对指针进行解除引用然后获取其地址是无操作的,因此这是j + "Programming" == "Programming" + j == "ogramming",因为字符串只是字符的数组。
对于执行另一个分支来说,也是一样的,这是因为2 ^ 3 == 1 != 2。

1
为什么在 printf(&j["Programming"], &k["Theory"]); 中第二个字符串 "Theory" 没有被打印出来?实际上,我对于为什么在 printf 函数中有两个字符串感到困惑。 - swag2198
3
printf 的第一个参数是“格式化字符串”,其后的所有参数都被插入到该字符串中包含以“%”开头的格式化说明符所在的位置。由于“ogramming”没有这样的格式化说明符,因此第二个参数会被简单地忽略。 - Peter
哦,我明白了!所以如果第一个字符串中有一些“...%s ...”,那么第二个字符串也会被打印出来,对吧? - swag2198
2
@swag2198:是的,没错(但如果有更多的格式说明符而没有足够的参数,那将导致未定义的行为)。 - Peter
谢谢Peter,今天我学到了printf的新知识。我之前遇到过i[a]格式的问题,但是我没有意识到它被应用在这里,因为我不习惯看到这样的printf语句。 - Prabhanshu Chandra

3
也许这个示例程序会向您展示幕后的数学运算:
#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;
}

输出

&j = 0x7fffb3325aa8

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

Print strings
&j["Programming"] = ogramming
p1 + j            = ogramming

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接