【问题标题】:What exactly does &(p[*(i + j)]) do?&(p[*(i + j)]) 到底是做什么的?
【发布时间】:2014-03-10 13:09:55
【问题描述】:

运行以下代码将打印出orld。这里发生了什么? &(p[*(i + j)]) 到底是做什么的?

#include <stdio.h>
char p[] = "HelloWorld";
int i[] = {2,1,3,5,6}, j = 4;

int main()
{
    printf(&(p[*(i + j)]));
    return 0;
}

【问题讨论】:

  • 提示:指针算法
  • p 是 char[] 并且你将 &p 传递给 printf。开头由表达式*(i+j) == 6 给出,它将打印整个字符数组,直到遇到转义字符\0。如果您只想打印该位置的字符,请尝试p[*(i+j)]
  • 这是执行吗?我希望没有人在现实生活中写出这样的东西。
  • stackoverflow.com/questions/381542/…开始,解释了最里面的部分。
  • @Jens:这是我偶然发现的一个练习。

标签: c


【解决方案1】:
char p[] = "HelloWorld";
int i[] = {2,1,3,5,6}, j = 4;

&amp;(p[*(i + j)]) 的评估如下:

这里的iarray ibase address。因此i+4 将是array ififth elementaddress*(i+j) 将等于 6P[6]W 之后将是o&amp;(p[*(i + j)])等于&amp;p[6]。因此,在printf 中,您传递的是address of o,而输出 将是orld

【讨论】:

  • 所以 printf(&p[6]) 将打印数组 p 的内容,直到它到达 \0?这个机制怎么称呼?
  • @mcwise 是的。 printf 获取要打印的字符串的地址并打印字符串,直到它到达 \0
【解决方案2】:

让我们从了解以下几个事实开始:

1) 数组是分配内存位置的序列。数组标签本身是序列的第一个元素的内存位置的地址。示例:

int asd[5] = { 11, 12, 13, 14, 15 };    // <-- this is an array

/* the following is what it looks like in the memory:
11  12  13  14  15

the value of, for example, asd[4] is 15
the value of asd itself is the memory address of asd[0], the very first element
so the following is true:
asd == &asd[0]  */

2) 当程序遇到字符串文字时,即双引号内的任何内容,例如您的示例中的"HelloWorld",它会用这些字符填充一些内存位置,然后再填充一个字符, '\0' 作为结束标志,让程序知道什么时候停止;然后,它返回第一个字符的内存位置。所以换句话说,"HelloWorld" 单独创建了一个数组并返回该数组的标签。

3) asd[3]*(asd + 3)3[asd],都是一样的;它们都指向地址为asd + 3 的内存位置的内容。 asd 的指针类型在这里很重要,它决定了从asd 偏移多少位/字节。至于int * asdasd + 3 会提前3 * sizeof ( int ) 字节在asd 之前。

现在,让我们来看看&amp;( p[ *(i + j) ] )到底是什么:

    &( p[ *( i + j ) ] )
    &( p[ *( i + 4 ) ] )
    &( p[    i[4]    ] )
    &( p[      6     ] )    // This will return the address of `7th` element to the printf. 
     ( p      +      6 )    // A pointer to second 'o'

然后这被推入printf作为const char *参数,它打印'o',然后是'r',然后是'l',然后是'd',然后遇到'\0',这样就明白了字符串结束并停在那里。

【讨论】:

  • 很好的解释。 +1。但是您应该删除行&amp;( "HelloWorld"[6] )"HelloWorld" + 6。这对新手来说有点混乱。
【解决方案3】:

我会逐步简化它

#include <stdio.h>
char p[] = "HelloWorld";
int i[] = {2,1,3,5,6}, j = 4;

int main()
{
    printf(&(p[*(i + j)]));
    return 0;
}

前三行很明显:

  • p 是一个 10 个字符的数组
  • i 是一个由 5 个整数组成的数组
  • j 是一个整数,值为 4

printf(&amp;(p[*(i + j)]));

相同

printf(&amp;(p[*(i + 4)]));

相同

printf(&amp;(p[*([adress of first element of i] + 4)]));

相同

printf(&amp;(p[*([adress of fourth element of i])]));

现在您必须知道*address 为您提供了address 中的值。所以:

printf(&amp;(p[6]));

这就是我猜你正在苦苦挣扎的地方。你必须知道:

  • 数组基本上没有别的东西 而不是记忆中连续的部分。它由它的起始地址指定。
  • &amp;something 给你something 的地址

所以这会将数组HelloWorld“切片”为orld。在 Python 中你会写成 p[6:],在 C 中你会写成 &amp;p[6]

【讨论】:

    【解决方案4】:

    我们一步一步来:*(i+j)i[j]一样,就是6p[6] 是 p 指针处的值加 6。

    运算符的地址得到那个字符的地址,因此是char*

    一个指向p第6个字符的char指针传递给printf函数打印文本“orld”。

    【讨论】:

      【解决方案5】:

      &amp;(p[*(i + j)]) 导致下面的表达式,即p[6] 的地址为j = 4

      &amp;(p[*(i + j)]) == &amp;(p[(i[j])]) == &amp;(p[(i[4])]) == &amp;(p[6]) == &amp;p[6]

      是的,您可以使用不带格式 %s 说明符的 printf 进行打印,因为它将字符串作为参数。

      【讨论】:

        【解决方案6】:

        阅读 cmets 进行解释

        #include <stdio.h>
        char p[] = "HelloWorld";
        int i[] = {2,1,3,5,6}, j = 4;
        
        int main()
        {
            printf(&(p[*(i + j)])); //*(i+j) = i[j] => i[4]= 6
            // &(p[*(i + j)]) => place the pointer in memory block that his address p[6]
            // so printf print the string starting from the p[6] ie from 'o' => orld
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 2014-06-14
          • 2011-12-28
          • 2020-03-28
          • 2021-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多