为什么不同类型的指针用于c中的不同数据类型?

如果我们必须保存任何数据类型的地址,那么我们需要该数据类型的指针。 但是指针只是一个地址,并且地址总是int类型,那么为什么任何数据类型的保持地址都需要该类型的指针?

有几个原因:

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

请注意,在C中有一个指针类型,意思是“简单的指针”,称为void* 。 您可以使用此指针在内存中传输地址,但是您需要将其转换为有用的内容,以便在void*指向的内存中执行操作。

指针不只是int 。 它们含蓄地具有语义。

以下是几个例子:

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

  • p = p+1; 根据您指向的对象的大小而行为不同(在某种意义上,’p’实际上增加了,当被视为无符号整数时,它指向的类型的大小)。

您可以非常轻松地在C中使用无类型指针 – 您只需对所有指针使用void * 。 尽管出于两个我能想到的原因,这将是相当愚蠢的。

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

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

以下示例有助于理解不同类型的指针之间的差异:

 #include  int main() { // pointer to char char * cp = "Abcdefghijk"; // pinter 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+1ip+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)); 

与输出

在此处输入图像描述

因此,为了更好地理解阅读教程

因为你假设“地址总是int类型”是错误的。

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

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

考虑:

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

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

这主要是针对那些在您之后阅读代码的人,因此他们可以知道存储在该地址的内容。 此外,如果你在你的代码中做任何指针算术,编译器需要知道如果你执行像指针类型给出的pSomething ++这样的东西,他应该向前推进多少,因为你的数据类型的大小是编译前已知。

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

示例: – 如果char只有1个字节
在int 2字节的情况下可能会有所不同。