0

我以为我理解了指针语法,但有一些小事让我感到厌烦,例如:

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);

4

6 回答 6

7

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

int *ptr;

如果你已经声明

int a;

这意味着什么?这意味着a是一个int. 同样,由于您已声明int *ptr;,这意味着它*ptr是一个int.

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

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

所以当你有

ptr = array;

您正在将数组第一个元素的地址分配给指针ptr。由于这是一个 的数组int,因此您将 an 的地址分配int给一个可以保存 an 地址的变量int。赋值的左边和右边是同一种值。

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

*ptr = array; 

意思是:取右边的值,并用这个右边的值替换所持有的地址的 值。这是错误的,原因有两个。ptr

  1. array是一个地址。它不完全是整数值。它只是记忆中的一个位置。当然,该位置可以用整数表示,就像美国的位置可以用整数邮政编码表示一样,但正如您通常不关心邮政编码的数值是什么一样,您可能不关心也不在乎给定内存地址的整数值是多少。
  2. ptr未初始化。回到我们之前的例子:int a;. 的价值是a多少?我们还没有为它设置一个值,所以它只是垃圾。同样,ptr还没有指向任何东西。它可以指向一个整数,但我们还没有告诉它指向哪个整数。没有地址ptr。我们不能说“用ptr这个新值替换当前值”,因为ptr根本还没有指向任何值;我们还没有告诉它从哪里开始。

总结一下:通过编写ptr = array;您正在做的事情是完全正确的——将指向 an 的指针分配给inttype 的变量pointer to an int。通过写入*ptr = array;,您会将地址分配给整数,这可能不是您的意思;其次,由于整数本身没有分配在内存中的任何位置,因此分配无处可去。

这就是为什么ptr = array;是正确的,而且*ptr = array是完全错误的。

关于函数指针的问题是一个单独的问题,所以请问一个关于func(ptr)vs.的不同问题func(*ptr)

于 2013-09-02T00:31:53.150 回答
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)

于 2013-09-01T22:48:00.520 回答
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.
于 2013-09-01T22:51:24.993 回答
1

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

*ptr = array

请记住,这里*是间接运算符。它返回指针指向的内存位置的对象。此外,在此上下文中array被转换为指针。所以上面的行为指向的对象分配了一个指针即内存地址)。这只有在指向指针时才有效。但是,指向一个代替。ptr ptrptrint

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

于 2013-09-01T23:48:03.407 回答
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 的地址存储在 x_ptr 中。

   +-------+
   |  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]
+-----------+

这里数组 = 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
于 2013-09-02T05:49:33.150 回答
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]as*(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数组元素

于 2013-09-02T07:45:08.737 回答