【问题标题】:Pointers in C, why this output?C中的指针,为什么要输出这个?
【发布时间】:2017-11-10 08:59:15
【问题描述】:

嘿,我对 C 编程相当陌生,我正在尝试理解指针和地址并运行此代码,我得到了输出: v = 3003 '一个内存地址' *p = 3003

我理解最后两个,但有人可以帮助解释为什么 v = 3003?我最初的理解是它会导致 3002,所以我理解寻址和指针行 'p = &v' 在其中发挥了作用,但我不明白如何。任何解释将不胜感激谢谢!

#include <stdio.h>
int main() {
    int v = 0x3002;
    int* p = 0x3000;
    p = &v;
    (*p)++;
    printf("v = %x\n", v);
    printf("%x\n", p);
    printf("*p = %x\n", *p);
}

【问题讨论】:

  • p 指向 v。你增加 p 指向的地方,所以你增加 v。所以 v 是 3003。
  • 您的预期和实际输出是多少?请edit您的问题并在此处明确说明。
  • (*p)++; 是此处v++ 的另一种说法。简而言之,您正在做v=v+1。对指针进行一些研究。
  • 它说?我的实际输出是 3003,但预期输出是 3002?
  • printf("%x\n", p); --> printf("%p\n", (void*)p);

标签: c pointers


【解决方案1】:

您的代码行为未定义。您不能将地址分配给与您不拥有的内存相对应的指针,NULL、数组末尾的一个或标量末尾的一个例外。 (出于某种原因,这是一个鲜为人知的规则。)

所以你的首要任务是删除int* p = 0x3000;。替换为int* p;。然后未定义的行为消失。

你的代码

p = &v;
(*p)++;

p设置为v的地址,并通过指针递增v

【讨论】:

  • int* p = 0x3000; 本身可能是未定义的,但是当我们在下一行重新分配p 时,程序的结果是否真的未定义?
  • @MichaelWalz:是的。一位 UB 等于整个程序 UB。虽然我会将一个由于任意初始化而吃掉你的猫的编译器放入严重敌对类别,并切换供应商。
  • 取消引用无关紧要。我说的是任务。是的,当你第一次发现这条规则时,它会产生与你发现圣诞老人不存在时类似的反应。 你不能分配任何东西。
  • @Bathsheba.: 能否请您出示标准摘录?
  • 我不是想更改代码,我实际上是从过去的考试问题中获取的,它希望我识别输出。
【解决方案2】:

p=&amp;v 语句将变量v 的地址分配给p。换句话说,从那时起,p 将指向v 存储其值的内存地址。然后(*p)++ 递增它:p 是内存中的一个指针,*p 正在取消引用这个地址,因此递增操作 ++ 不适用于 p(在这种情况下,p 将指向下一个内存地址),而是p给出的地址处的值。

【讨论】:

    【解决方案3】:

    p = &amp;v;

    p 现在包含v 的地址。

    (*p)++;

    增加p 中包含的地址处的值。该值为0x3002;

    所以它变成了0x3003

    现在v 已通过p 更改。

    这就是输出的原因。

    您可以通过强制转换分配给指针。

    int *p=(int*)0x3000;
    

    代码将是:-

    #include <stdio.h>
    int main() {
        int v = 0x3002;
        int* p;
        p=&v; 
        (*p)++;
        printf("v = %x\n", v);
        printf("%x\n", p);
        printf("*p = %x\n", *p);
    }
    

    另外分配给指针变量是未定义的行为

    来自标准§6.3.2.3

    整数可以转换为任何指针类型。除了作为 之前指定,结果是实现定义的,可能 未正确对齐,可能未指向 引用类型,可能是陷阱表示。)

    【讨论】:

    • int *p = 0x3000; 在 C 中是合法的(无需强制转换),您只会收到警告。但无论如何,这无关紧要。
    • @MichaelWalz.: 刚才提到了....我一开始以为它是 dererenced..但事实并非如此。检查代码一次。
    • 这就是我对为什么 p = 3003 的理解,所以如果两个不同的变量共享相同的地址,对一个变量的任何更改也会改变另一个变量?
    • @thin580.: 变量永远不能有相同的地址....但是通过指针我们可以修改另一个...如图所示。
    • @thin580 p = 3003 无关紧要。如果您只写int* p;,代码将是相同的,因为p 无论如何都会在下一行重新分配。
    【解决方案4】:

    首先,在详细介绍pointer之前,C语言提供的Memory access这样使用是很危险的。通常,您不会像代码中提到的那样定义要保存变量的位置的地址或指针本身的地址。

    #include <stdio.h>
    int main() {
        int v = **0x3002**;
        int* p = **0x3000;**
        p = &v;
        (*p)++;
        printf("v = %x\n", v);
        printf("%x\n", p);
        printf("*p = %x\n", *p);
    }
    

    但是,您分配给 p 的值被忽略,因为您使用的是 p = &v , p 具有由编译器或操作系统分配给 v 的正确地址。当你定义 int v;在运行时分配内存位置,然后 p 将获得地址。

    一般来说,您试图创建一个整数变量和一个指向该变量的指针,以便对同一个变量有两个引用。

    一般来说,你在使用变量或指针时不需要跟踪它们的地址值,你只需要知道如何正确使用它们以及何时使用它们

    指针使用的一般示例

    #include <stdio.h>
    void changeA( int*);
    int main() {
       int a=1;
       printf("%d",a);
       changeA(&a);
       printf("%d",a);
       return 0;
    }
    
    void changeA(int* pA){
      *pA=2;
    }
    

    输出 1 2

    前面的例子展示了指针的使用,你可以在不同的范围内访问变量,变量a在主函数的范围内定义,并通过为函数提供变量a的地址来使用指针changeA该函数可以访问内存中变量a保存的内存位置,并直接从另一个函数范围更改它。

    通常当您需要为一个函数提供多个输出时使用指针,并且 return 可用于仅返回一个变量。使用指针,您将拥有每个功能的无限功能。

    【讨论】:

      【解决方案5】:

      这是已发布代码的正确编写版本,带有适当的 cmets

      #include <stdio.h>
      
      int main( void ) 
      {
          int v = 0x3002;   // sets an integer value into 'v'
          int* p = &v;      // get address of 'v' and places that address in 'p'
          (*p)++;           // increments the contents of 'v', 
                            // using 'p' 
                            // while paying attention to operator precedence in C
      
          // displays on terminal, the contents of 'v' I.E.0x3003
          printf("v = %x\n", v);   
      
          // displays on terminal, the address of 'v' (contents of 'p')
          printf("%p\n", (void*)p);
      
          // displays on terminal, the contents of 'v', which is pointed to by 'p'
          printf("*p = %x\n", (unsigned int)*p);
      }
      

      【讨论】:

        猜你喜欢
        • 2016-05-23
        • 1970-01-01
        • 2019-07-25
        • 2021-01-16
        • 1970-01-01
        • 2011-10-04
        • 2014-06-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多