声明指针类型?

时间:2013-12-05 18:24:52

标签: c++ c pointers

我刚才读到我们需要在用C(或C ++)声明它们时给出指针类型,即:

int *point ;

据我所知,指针存储变量的地址,并且地址占用相同数量的内存,无论类型如何。 那么,为什么我们需要声明它的类型?

10 个答案:

答案 0 :(得分:70)

类型安全。如果您不知道p应该指向什么,那么就没有什么可以阻止类别错误,如

*p = "Nonsense";
int i = *p;

静态类型检查是一种非常强大的工具,可以防止出现各种类型的错误。

C和C ++也支持指针算法,只有在目标类型的大小已知时才有效。

  

地址占用相同数量的内存,无论我的类型是什么

今天流行的平台也是如此。但是有些平台并非如此。例如,指向多字节字的指针可能小于指向单个字节的指针,因为它不需要表示字中字节的偏移量。

答案 1 :(得分:34)

由于:

  1. 针对不同类型的地址不需要具有相同的尺寸。该标准明确指定了(C 2011 standard(在线草案),6.2.5 / 28)。
  2. type-safety:这允许编译器检测何时提供指向函数或赋值的不兼容指针。这反过来可以防止将参数顺序搞砸到函数的丑陋情况。
  3. 编译器需要知道指针解除引用时的类型。
  4. 做指针运算,指向的对象的大小需要知道,因此需要知道它的类型。
  5. 最后两点不适用于void指针,这就是为什么它们不能被解除引用而且不能对它们进行指针运算。该标准指定void指针必须足够大以容纳任何类型的指针(除了函数指针,这是一个完全不同的故事),并且可以在没有强制转换的情况下对void指针进行赋值。 (至少在C中,总是需要C ++演员表)

答案 2 :(得分:13)

一个原因是指针算法。除非您知道p+1指向的元素的大小,否则您无法执行p - 这是p为指针的类型的大小。如果您在p+1上尝试void *p,则可能会得到一个错误的答案(这与char *上的答案相同,但也许您不希望这样做;它被-pedantic作为警告捕获,并被-pedantic-errors作为错误捕获。

另一个原因是类型安全。如果函数接收int *作为参数,则无法在那里传递指向char(字符串)的指针。您会收到警告(-Werror / -pedantic-errors出错)。考虑这个(虚拟)代码:

void test(int *x)
{
}

int main()
{
    char *x = "xyz";
    test(x);
    return 0;
}

编译(使用gcc (GCC) 4.8.2 20131017 (Red Hat 4.8.2-1))给出:

1.c: In function ‘main’:
1.c:8:2: warning: passing argument 1 of ‘test’ from incompatible pointer type [enabled by default]
  test(x);
  ^
1.c:1:6: note: expected ‘int *’ but argument is of type ‘char *’
 void test(int *x)
      ^

答案 3 :(得分:11)

  

那么,为什么我们需要声明它的类型?

您想知道指针的类型,以便您可以static type checking

我们还需要知道pointer arithmetic的工作类型,例如当我们索引到不同大小类型的数组(等同于指针算术)指针时将根据类型依赖金额进行调整。如果我们查看草案C99标准部分6.5.6 添加运算符说(强调我的):

  

另外,两个操作数都应具有算术类型,或者一个操作数应为a   指向对象类型的指针 [...]

因此指针必须是对象类型,这意味着不完整或无效。

你也说过:

  无论类型如何,

地址都会占用相同数量的内存。那么,为什么我们需要声明它的类型?

C ++ 中并不总是如此。成员函数指针的大小可以根据类类型而改变,其中一篇优秀的文章是Pointers to member functions are very strange animals

此外,我们可以看到C99草案标准部分6.2.5 类型段落 27 ,其中包含:

  

[...]指向其他类型的指针不需要具有相同的表示或对齐要求。

和草案C ++标准部分3.9.2 复合类型 3 说:

  

[...]指针类型的值表示是实现定义的。符合cv资格和cv不合格版本(3.9.3)的布局兼容类型的指针应具有相同的值表示和对齐要求(3.11)。 [...]

除特定情况外,

不要求指针具有相同的表示

答案 4 :(得分:8)

您需要将类型指定为标准要求。 此外,当您尝试执行加法或减法等指针运算时,没有任何问题。

答案 5 :(得分:5)

指针的类型在解除引用和指针算术时起作用。 例如

int x=10;     //Lets suppose the address of x=100
int *ptr=&x;   //ptr has value 100
printf("The value of x is %d", *ptr);
ptr++;  // ptr has value 104(if int is 4bytes)

在上面的例子中,指针类型是int,因此编译器将从内存地址100开始查找存储在接下来的4个字节中的值(如果int是4bytes)。所以指针的类型告诉编译器有多少它应该在解除引用时寻找的字节数。如果指针类型不存在,编译器将如何知道在解除引用时要查看多少字节。当我们做 ptr ++ 时,指针的类型告诉ptr应该增加多少。这里ptr增加4.

char c='a';   //Lets suppose the address of c = 200
char* ptr=&c;   //ptr has value 200
ptr++;   //ptr has value 201(char assumed to be 1 byte) 

指针类型告诉ptr增加1个字节。

答案 6 :(得分:5)

虽然处理器通常有不同的指令“从地址加载一个字节”,“从地址加载一个16位半字”,“从地址加载一个32位字”,同样用于“存储”操作,C使用相同的语法从地址加载一个字节,以加载任何其他大小的值。鉴于声明:

int n = *p;

编译器可以生成从p中的地址加载字节,半字或字的代码并将其存储到n中;如果p是一个* float,它可能会生成一个更复杂的代码序列来加载c中的浮点值,截断它,转换为int,并将转换后的值存储到n中。在不知道p的类型的情况下,编译器无法知道哪种操作是合适的。

同样,声明p++可能会将p中的地址增加一,二,四或其他数字。地址增加的数量将取决于声明的p类型。如果编译器不知道p的类型,它将不知道如何调整地址。

可以声明指针而不指定它指向的事物的类型。这种指针的类型是void*。在对它做任何有用的事情之前,必须将void*转换为真实的指针类型; void*的主要用处在于如果指针转换为void*,它可以通过代码传递给void*,该代码对指针的实际类型一无所知。如果指针最终被赋予 知道其类型的代码,并且该代码将指针强制转换回该类型,则结果将与已转换为{{1}的指针相同}。

代码必须处理它所知道的事情的指针通常可以有效地使用void*用于此类目的,但是知道指针所指向的事物的代码通常应该声明正确类型的指针。

答案 7 :(得分:3)

这样它就可以执行算术运算和其他运算。 考虑以下两个例子:

int* p; /* let the address of the memory location p pointing to be 1000*/
p++;
printf("%u",p); /* prints 1004 since it is an integer pointer*/


char *p; /* let the address of the memory location p pointing to be 1000*/
p++;
printf("%u",p); /* prints 1001 since it is an char pointer*/

我希望这可以帮到你!

答案 8 :(得分:0)

我们实际上没有需要(见下文)来声明类型,但我们应该。指针存储有关对象位置的信息,而类型定义了内存占用的空间。

在各种情况下需要存储在指向内存中的对象的大小 - 数组创建,分配,复制内存,最后 - 使用new创建对象。

但是,如果要隐藏(出于任何原因)类型,您仍然可以定义void指针:

void* dontKnowWhatTypeIsHere;

void指针被认为是通用指针。它可以指向任何对象,当我们想要将它与类型一起使用时,我们只会reinterpret_cast

答案 9 :(得分:-5)

很多上述声明但是apan纯粹是正确的。 现在你的问题 为什么我们定义指针类型? 指针的第一个定义 一个指针,可以保存另一个变量的地址。 以上定义是部分的。确切的定义是 pointer是一个可以保存变量地址的变量,如果我们取消引用(获取值),它将返回该地址上当前的值。如果指针未能在取消引用时返回值,则它不是指针。 您可以尝试即使在gcc编译器中,一个简单的变量也可以保存另一个变量的地址但是在取消引用时它会给你错误。 现在的大小 无论数据类型如何,指针的大小始终等于特定编译器上的整数大小。因此gcc编译器中指针的大小为4bytes(整数大小),而在turboc中,其大小为2bytes(整数大小)。   现在问题是为什么等于整数的大小。 任何变量的地址是什么,它可能是int,char,float等,地址总是一个整数,整数整数都存储在int中。这就是为什么指针的大小等于int的大小,因为它还存储了始终是纯整数数据的地址。  那么任何其他数据类型指针的int和char之间有什么区别。在检索时,您的编译器将根据您的数据类型获取字节数,否则您将获得错误或不是错误,但对您来说有一些不可预测的结果但不适合我。 同样的规则适用于递增和递减指针,它总是根据指针数据类型递增和递减。  指针的大小不依赖于数据类型,因此你的链接列表进入图片的原因是因为如果你试图在同一个变量中声明结构,那么你将得到编译时错误,因为你的编译器不是在完成声明之前的结构但允许相同结构的自引用指针为什么?唯一的答案是因为指针的大小不依赖于数据类型的大小。如果您有任何疑问,请咨询我。 谢谢 asif aftab