函数中的指针语法

时间:2013-09-01 22:44:35

标签: c pointers

我认为我理解了指针语法,但是有一些小事件让我失望,例如:

int *ptr;
int array[4] = {1,2,3,4};
int *arrayEnd = array + n;

for (ptr = array; ptr < arrayEnd; ++ptr)
    sum += *ptr;

return sum;

在定义ptr = array循环时,我们怎么做*ptr = array而不是for

我也不明白为什么当函数的参数是指针时,我们不使用星号。

我在书中看到了function(ptr);,但为什么不这样:function(*ptr);

6 个答案:

答案 0 :(得分:7)

让我们从代码的第一行开始:

int *ptr;

如果您已宣布

int a;

这是什么意思?这意味着aint。同样,由于您已声明int *ptr;,这意味着*ptrint

如果*ptrint,那么ptr是什么? ptr(没有星号)是指向 int指针。 指针是一个保存值地址的变量。在这种情况下,指针是指向int的指针,这意味着ptr所持地址的值为int

然后你有int array[4] = {1,2,3,4};。声明和定义数组时,数组标识符(数组的名称)会告诉您数组在内存中的位置。在任何表达式中使用时,数组的名称会衰减到数组的第一个元素的地址。

所以当你有

ptr = array;

您要将数组的第一个元素的地址分配给指针ptr。由于这是int的数组,因此您将int的地址分配给可以保存int地址的变量。赋值的左侧和右侧是相同类型的值。

为什么ptr而不是*ptr?在这种情况下,*是什么?它是一元解除引用/间接运算符。所以

*ptr = array; 

意味着:取右侧的值,并使用此右侧值替换 ptr 所占地址的值。出于两个原因,这是错误的。

  1. array是一个地址。它不完全是整数值。它只是记忆中的一个位置。当然,该位置可以用整数表示,美国的位置可以用整数邮政编码表示,但就像你通常不关心邮政编码的数值是什么一样,你可能不会我真的关心给定内存地址的整数值是什么。
  2. ptr未初始化。回到我们之前的例子:int a;a的价值是多少?我们还没有为它设置一个值,所以它只是垃圾。同样,ptr还没有指向任何东西。 可以指向一个整数,但是我们还没有告诉它指向什么整数。 ptr没有地址。我们不能说“用这个新值替换ptr指向的当前值”,因为ptr尚未指向任何值;我们还没有告诉它从哪里开始。
  3. 总结一下:通过编写ptr = array;您正在做的事情是完全正确的 - 将int的指针指定给pointer to an int类型的变量。通过编写*ptr = array;,您将为整数分配一个地址,这可能不是您的意思;其次,由于整数本身没有在内存中的任何地方分配,因此分配无处可去。

    这就是为什么ptr = array;是正确的,*ptr = array会出错。

    关于函数指针的问题是一个单独的问题,因此请询问有关func(ptr)func(*ptr)的其他问题。

答案 1 :(得分:3)

您可以将传统的,基于索引的迭代转换为仅使用指针算法的迭代:

T array[N];

// traditional:

for (size_t i = 0; i != N; ++i)
{
    foo(array[i]);
}

// using pointer arithmetic

for (T * p = array; p != array + N; ++p)
{
    foo(*p);
}

指针T * p = array是通过将数组名称衰减到指向其第一个元素的指针获得的。这两种形式之间的联系是基本身份array[i] == *(array + i)

答案 2 :(得分:1)

int *ptr, i;
int array[20];

ptr  = &i;        // make sure ptr points somewhere valid
ptr  = array;     // put the address of array[0] in the variable ptr
*ptr = array;     // put the address of array[0] into the location ptr points to
ptr  = array[0];  // put the integer in array[0] into the variable ptr
*ptr = array[0];  // put the integer in array[0] into the location ptr points to.

答案 3 :(得分:1)

让我们看看你建议的代码:

*ptr = array

请记住,*是间接运算符。它返回指针指向的内存位置的对象。此外,在此上下文中,array将转换为指针。因此,上面的行将指针(即内存地址)分配给对象ptr 指向。这只有在ptr指向指针时才有效。但是,ptr会指向int

另一方面,ptr = array是正确的,因为指定ptr指向数组中的第一个元素。

答案 4 :(得分:1)

假设你有类似下面的代码。

int x=10;

这里x是一个保存值为10的变量。变量x只是某个内存地址的标签。

        x
    +-------+
    |  10   |    4050 which is x
    +-------+

因此值10存储在4050中。它总是很难记住内存地址。因此,您可以通过命名并使用该名称来轻松实现。这里的x只是内存地址4050的标签。

int *x_ptr;

这里x_ptr是一个指针变量,可以存储任何整数变量的内存地址。

   +-------+
   |  GBV  |   5000 which is x_ptr
   +-------+

这里x_ptr是地址5000的标签。最初该变量将包含垃圾值(GBV)。

x_ptr = &x;  

以上语句在x_ptr中存储x的地址。

   +-------+
   |  4050 |   5000
   +-------+
 x_ptr = &x = 4050
 printf("%u",x_ptr); // 4050
 printf("%d", *x_ptr); // 10

 *x_ptr = *(4050) = valueAt(4050) =  10  

现在让我们讨论一下你的代码。

int *ptr;

+-------+
|  GBV  |   6000 which is ptr
+-------+

int array[4] = {1,2,3,4};

+-----------+
|     1     |    7824 which is array+0 or array[0]
+-----------+
|     2     |    7828 which is array+1 or array[1]
+-----------+
|     3     |    7832 which is array+2 or array[2]
+-----------+
|     4     |    7836 which is array+3 or array[3]
+-----------+

这里array = 7824

int *arrayEnd = array + n; 

根据数据类型增加内存位置将增加字节数。

array+0 = 7824 + 0 = 7824
array+1 = 7824 + 1(4 bytes in case of integer) = 7824 + 4 = 7828
when n=4
    arrayEnd = 7824 + 16 =  7840
+-------+
|  7840 |   6010 which is arrayEnd
+-------+

for (ptr = array; ptr < arrayEnd; ++ptr)
   sum += *ptr;

这里ptr用数组的基地址初始化(7824)。所以7824将存储在内存6000中。

  6000             6000    
+-------+        +-------+
|  GBV  |   =>   | 7824  |   6000 which is ptr
+-------+        +-------+

所以现在ptr = 7824

For Loop
+-------+--------------+-------------+    
|  ptr  |   *ptr       | sum + =*ptr |  // 7824 < 7840
+-------+--------------+-------------+
|  7824 | *(7824) = 1  |  sum += 1   |  // 7828 < 7840
+-------+--------------+-------------+
|  7828 | *(7828) = 2  |  sum += 2   |  // 7832 < 7840
+-------+--------------+-------------+
|  7832 | *(7832) = 3  |  sum += 3   |  // 7836 < 7840
+-------+--------------+-------------+
|  7836 | *(7836) = 4  |  sum += 4   |  // 7840 !< 7840 so loop terminates
+-------+--------------+-------------+ 

为什么ptr = array而不是* ptr = array?

valueAt(*) has to be used when you have to store some value in the memory address.

ptr= array; //initializing base address of array to ptr.

  6000             6000    
+-------+        +-------+
|  GBV  |   =>   | 7824  |   6000 which is ptr
+-------+        +-------+

*ptr = array; // ptr already has a address pointed to, and you store array's base address inside that memory location.

  6000     
+-------+  
|  GBV  |    *ptr= *(GBV) = Unknown = array  // No guarantee that GBV is a proper memory address
+-------+  

如果ptr已经有一些正确的内存地址说1000,那就像

  6000     
+-------+  
| 1000  |    *ptr= *(1000) = valueAt(1000) = array 
+-------+  

which makes

  1000     
+-------+  
| 7824  |    
+-------+ 

多指针的简单示例。

#include<stdio.h>
int main()
{
    int x=10;
    int *y=&x;
    int **z=&y;
    printf("%d --> %d --> %d",x,*y,**z); 
    return 0;
}

OUTPUT:
   10 --> 10 --> 10

答案 5 :(得分:0)

请注意,星号含义在定义上有所不同。当你写:

int *arrayEnd = array + n;

它实际上与:

相同
int *arrayEnd;
arrayEnd = array + n;

在这两种情况下,都会初始化指针的地址,而不是指针引用的值

另请注意,在定义数组时,数组名称可以被视为数组的第一个内存位置,而括号中的数字是其偏移量,即接下来的两行是相同的:

ptr = array;
ptr = &array[0];

以及接下来的两行:

array[2] = 5;
*(array+2) = 5;

关于最后一个例子的有趣事实是它可以解释你有时可以写: 2[array]代替array[2] *(2+array)*(array+2)相同

所以当你写:

int *ptr;
int array[4] = {1,2,3,4};
int *arrayEnd = array + n;

for (ptr = array; ptr < arrayEnd; ++ptr)
    sum += *ptr;

return sum;

第三行将最后一个array元素的内存地址放在一个名为arrayEnd

的变量中

for循环从第一个array位置到最后一个array位置

sum添加数组元素