【问题标题】:Why are there different types of pointers for different data types in C?为什么 C 中不同的数据类型有不同类型的指针?
【发布时间】:2012-09-13 21:25:18
【问题描述】:

如果我们必须保存任何数据类型的地址,那么我们需要该数据类型的指针。

但是指针只是一个地址,地址总是int 类型。那为什么任何数据类型的保存地址都需要该类型的指针呢?

【问题讨论】:

  • 指针中的信息(从 C 的角度来看)比它的地址更多。也有类型。如果您的指针没有类型,那么取消引用它意味着什么?
  • 如果你用 BCPL 和 B(C 的前身)或汇编语言编写,你会得到,指针=整数。在 C 中加载指针:它们被设计为指向可能不同大小的东西,可能位于不同的内存中。如果指针只是纯整数而不是其他任何东西(尽管在引擎盖下它们仍然是整数,但这只有在编译器已经处理了所有类型和大小信息时),则无法实现取消引用此类指针。

标签: c


【解决方案1】:

有几个原因:

  • 并非所有地址都是平等的;特别是,在非冯诺依曼(例如Harvard)架构中,指向代码内存(通常存储常量)的指针和指向数据内存的指针是不同的。
  • 您需要知道底层类型才能正确执行访问。例如,读取或写入 char 不同于读取或写入 double。
  • 您需要更多信息来执行指针运算。

请注意,在 C 语言中有一种指针类型表示“只是一个指针”,称为 void*。您可以使用此指针来传输内存中的地址,但您需要将其转换为有用的东西才能在void* 指向的内存中执行操作。

【讨论】:

    【解决方案2】:

    指针不仅仅是int。它们隐含地具有语义。

    这里有几个例子:

    • p->member 仅在您知道 p 指向的类型时才有意义。

    • p = p+1; 的行为取决于您指向的对象的大小(从某种意义上说,当被视为无符号整数时,“p”实际上会增加它指向的类型的大小)。

    【讨论】:

      【解决方案3】:

      下面的例子可以帮助理解不同类型指针的区别:

      #include <stdio.h>
      
      int main()
      {
          // Pointer to char
          char * cp = "Abcdefghijk";
          // Pointer to int
          int * ip = (int *)cp; // To the same address
      
          // Try address arithmetic
          printf("Test of char*:\n");
          printf("address %p contains data %c\n", cp, *cp);
          printf("address %p contains data %c\n", (cp+1), *(cp+1));
          printf("Test of int*:\n");
          printf("address %p contains data %c\n", ip, *ip);
          printf("address %p contains data %c\n", (ip + 1), *(ip + 1));
      
          return 0;
      }
      

      输出是:

      重要的是要了解address+1 表达式根据address 类型给出不同的结果,即+1 表示sizeof(addressed data),如sizeof(*address)。

      因此,如果在您的系统中(对于您的编译器)sizeof(int) 和 sizeof(char) 不同(例如,4 和 1),cp+1 和 ip+1 的结果也不同。在我的系统中是:

      E05859(hex) - E05858(hex) = 14702684(dec) - 14702681(dec) = 1 byte for char
      E0585C(hex) - E05858(hex) = 14702684(dec) - 14702680(dec) = 4 bytes for int
      

      注意:在这种情况下,具体的地址值并不重要。唯一的区别是指针持有的变量类型,这显然很重要。

      更新:

      顺便说一下,地址(指针)算术不受+1或++的限制,所以可以举很多例子,比如:

      int arr[] = { 1, 2, 3, 4, 5, 6 };
      int *p1 = &arr[1];
      int *p4 = &arr[4];
      printf("Distance between %d and %d is %d\n", *p1, *p4, p4 - p1);
      printf("But addresses are %p and %p have absolute difference in %d\n", p1, p4, int(p4) - int(p1));
      

      有输出:

      所以,为了更好地理解,请阅读the tutorial。

      【讨论】:

        【解决方案4】:

        你可以很容易地在 C 中拥有一个无类型指针——你只需对所有指针使用void *。这将是相当愚蠢的,尽管我能想到两个原因。

        首先,通过指定类型中指向的数据,编译器可以避免许多愚蠢的错误、拼写错误或其他错误。相反,如果您剥夺了编译器的这些信息,那么您肯定会花费大量时间来调试本不应该成为问题的事情。

        此外,您可能使用过“指针算法”。例如,int *pInt = &amp;someInt; pInt++;——将指针前进到内存中的下一个整数;无论类型如何,这都有效,并前进到正确的地址,但只有在编译器知道所指向内容的大小时它才能工作。

        【讨论】:

          【解决方案5】:

          因为您假设“地址始终是 int 类型”是错误的。

          完全有可能创建一个计算机体系结构,例如,由于某种原因,指向字符的指针大于指向单词的指针。 C 会处理这个问题。

          当然,指针可以被取消引用,当你这样做时,编译器需要知道你希望在相关地址找到的数据类型。否则它无法生成正确的指令来处理该数据。

          考虑:

          char *x = malloc(sizeof *x);
          *x = 0;
          
          double *y = malloc(sizeof *y);
          *y = 0;
          

          这两个 sn-ps 将写入完全不同数量的内存(或者如果分配失败,则爆炸,暂时不要介意),但实际的文字常量(0,其类型为 int)是相同的在这两种情况下。有关指针类型的信息允许编译器生成正确的代码。

          【讨论】:

          • 除此之外,指针数学取决于指针的类型。
          • 嗯,“完全有可能创建一个计算机体系结构......”是一个危险的探索之地。事实上,也可以创建一个用 C 编写的程序无法运行的程序,除非您使用某种非常慢的模拟器(只是不支持 C 规定的内存架构)。
          【解决方案6】:

          它主要适用于那些在您之后阅读代码的人,以便他们知道该地址存储的内容。此外,如果您在代码中执行任何指针运算,编译器需要知道如果您执行 pSomething++ 之类的操作,他应该前进多少,这是由指针的类型给出的,因为您的数据类型的大小是编译前就知道了。

          【讨论】:

            【解决方案7】:

            因为指针的类型告诉编译器一次你可以执行多少字节的操作。

            示例:char 的情况下,只有一个字节。并且在两个字节的int情况下可能会有所不同。

            【讨论】:

              猜你喜欢
              • 2022-07-22
              • 1970-01-01
              • 2023-04-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-10-18
              • 1970-01-01
              相关资源
              最近更新 更多