何时在指针赋值中使用*?

时间:2016-05-10 12:50:53

标签: c arrays variables pointers memory

当我学习C时,我经常看到指针。

我得到一个指针在内存中保存了一个不同位置的十六进制值。所以指针只不过是例如:0x7fff5fbff85c

每个指针也是一个不同的类型。

int var = 10;
int *ptr = &var;

这里的Ptr指向var的位置。要获取var的值,我必须使用*ptr取消引用指针。 像

printf("Var = %d", *ptr);

将打印`Var = 10;

但是,如果我执行指针的非内联声明,如:

int var = 10;
int *ptr;
ptr = &var;

当我实际将内存地址分配给指针时,我不必在第三行使用*。 但是当我得到一个带指针的函数时:

int var = 10;
void assignPointer(int *ptr) {
*ptr = 10;
}

哦,等等!在我写这篇文章时,我发现指针有两种不同的分配:

*ptr = 10;

ptr = &var;

有什么区别?我是在第一种情况下首先取消引用指针,将10分配给它所持有的位置? 在第二种情况下,我正在为指针分配实际位置。

我在使用*时有点困惑,何时不在分配方面。

如果我正在使用数组,为什么我需要指针呢?

int array[];

"阵列"这里已经存在十六进制内存位置。不能使它成为指针吗?所以,如果我想将数据分配给数组,我就不会写:

*array = [10, 2];

首先我取消引用,然后我分配。

我输了:(

编辑:也许它有点不清楚。 当你没有使用指针时,我不知道你何时必须使用*。 携带十六进制的所有东西都是指针对吗? 数组的变量名称带有它的十六进制内存位置。那么为什么它不是一个指针?

EDIT2:谢谢你们帮助了我很多的人!

7 个答案:

答案 0 :(得分:3)

我不知道你什么时候使用*当你使用指针而不是。携带十六进制的所有东西都是指针对吗?数组的变量名称带有十六进制内存位置。那么为什么它不是指针?

最后一件事 - 数组的名称是而不是指针;它不会在任何地方存储地址。定义数组时,它的布局或多或少如下:

         +---+                
    arr: |   | arr[0]        Increasing address
         +---+                       |
         |   | arr[1]                |
         +---+                       |
          ...                        |
         +---+                       |
         |   | arr[n-1]              V
         +---+

对于与数组元素arrarr[0]分开的对象arr[n-1],没有预留存储空间。 C不会将任何元数据(如长度或起始地址)存储为数组对象的一部分。

相反,有一条规则说明如果数组表达式出现在您的代码中且该表达式不是sizeof或一元&运算符的操作数,那么将被转换(“衰减”)为指针表达式,指针表达式的值将是数组的第一个元素的地址。

所以给出了声明

T arr[N]; // for any type T

然后以下是真的:

    Expression         Type        Decays to        Value
    ----------         ----        ---------        -----
           arr         T [N]       T *              Address of first element
          &arr         T (*)[N]    n/a              Address of array (same value
                                                      as above
          *arr         T           n/a              Value of arr[0]
        arr[i]         T           n/a              Value of i'th element
       &arr[i]         T *         n/a              Address of i'th element
    sizeof arr         size_t                       Number of storage units (bytes)
                                                      taken up by arr

表达式 arr&arr&arr[0]都会产生相同的(第一个元素的地址)数组与数组的地址相同,但它们的类型并不完全相同; arr&arr[0]的类型为T *,而&arr的类型为T (*)[N](指向N的指针 - T的元素数组) 。

  

携带十六进制的所有东西都是指针对吗?

十六进制只是二进制数据的特定表示;它本身并不是一种类型。并非所有可以用十六进制编写或显示的东西都是指针。我可以将值0xDEADBEEF赋给任何32位整数类型;这不会成为一个指针。

指针的确切表示可能因架构而异;它甚至可以在同一架构上的不同指针类型之间变化。对于平面内存模型(与任何现代桌面架构一样),它将是一个简单的积分值。对于分段体系结构(如旧的8086 / DOS天),它可以是页面#和偏移量的一对值。

指针可能没有用于存储它的类型那么宽。例如,旧的Motorola 68000只有24个地址线,因此任何指针值都只有24位宽。但是,为了使生活更轻松,大多数编译器使用32位类型来表示指针,而不使用高8位(2的幂是方便的)。

  

我不知道你什么时候使用*时使用指针而不是。

非常简单 - 当您想要引用指向的实体时,请使用*;当你想引用指针本身时,请将其关闭。

另一种看待它的方式 - 表达式 *ptr等同于表达式var,所以每当你想要引用内容时var使用*ptr。{

更具体的例子可能有所帮助。假设如下:

void bar( T *p )
{
  *p = new_value();  // write new value to *p
}

void foo( void )
{
  T var;
  bar( &var );  // write a new value to var
}

在上面的示例中,以下情况属实:

 p == &var
*p == var

如果我写了*p的内容,我实际上正在更新var。如果我写了p的内容,我会将其设置为指向var以外的内容。

上面的代码实际上是为什么指针存在的主要原因。在C中,所有函数参数都按值传递 ;也就是说,函数定义中的形式参数是与函数调用中的实际参数不同的对象。形式参数的任何更新都不会反映在实际参数中。如果我们按如下方式更改代码:

void bar( T p )
{
  p = new_value();  // write new value to p
}

void foo( void )
{
  T var;
  bar( var );  // var is not updated
}

p的值已更改,但由于p在内存中与var不同,因此var中的值保持不变。函数更新实际参数的 only 方式是通过指针。

因此,如果您要将事件p 更新为,请写信至*p。如果要将p设置为指向其他对象,请写信至p

int x = 0, y = 1;
int *p = &x; // p initially points to x
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
*p = 3;
printf( "&x = %p, x = %d, p = %p, *p = %d\n", (void *) &x, x, (void *) p, *p );
p = y; // set p to point to y
printf( "&y = %p, y = %d, p = %p, *p = %d\n", (void *) &y, y, (void *) p, *p );

此时你可能会问,“我为什么要在int *p = &x而不是p = y中使用星号?”在第一种情况下,我们声明 p作为指针并在同一操作中初始化它,并且声明语法需要*。在这种情况下,我们写信给p,而不是*p。这相当于写作

int *p;
p = &x;

另请注意,在声明中,*绑定到变量名,而不是类型说明符;它被解析为int (*p);

C声明基于表达式的类型,而不是对象。如果p是指向int的指针,并且我们想要引用指向的值,我们会使用*运算符取消引用它,就像这样:

x = *p;

表达式 *p的类型为int,因此声明写为

int *p;

答案 1 :(得分:2)

C语法很奇怪。声明变量时,*仅用于指示指针类型。它实际上并没有解除任何引用。因此,

int *foo = &bar;

好像你写了

int *foo;
foo = &bar;

答案 2 :(得分:1)

你的一个例子是无效的。 *ptr = 10;。原因是10是一个值,但没有分配给它的内存。

您可以将您的示例视为"指定要指向地址的内容"或者"某事物的地址是"。所以,

int *ptr是指向某个地址的指针。所以ptr = &val;表示ptr等于val的地址。然后你可以说*ptr = 10;val = 10;因为* ptr和val都在查看相同的内存位置,因此值相同。 (注意我没有说"指着")。

答案 3 :(得分:1)

你非常正确。

  

我是否在第一种情况下首先取消引用指针,将10指定给它所持有的位置?在第二种情况下,我将实际位置分配给指针。

完全。如您所见,这是两个逻辑上不同的操作。

  

“array”这里已经存在十六进制内存位置。这不是指针吗?

你也掌握了它。为了您的理解,我会说数组是指针。然而实际上它并不那么简单 - 在大多数情况下,数组只会衰减成指针。如果你真的喜欢这件事,你可以在这里找到几个很棒的帖子。

但是,因为它只是一个指针,所以你不能“分配给数组”。如何在指针上下文中处理数组通常在“字符串”部分的任何C书中以相当好的方式解释。

答案 4 :(得分:1)

指针声明类似于常规变量。星号字符在声明期间位于指针名称之前,以将其区分为指针。声明您没有取消引用,例如:

int a = 0;
int *p = &a // here the pointer of type int is declared and assigned the address of the variable a

在声明语句之后,要为指针指定地址或值,请使用不带星号字符的名称,例如:

int a;
int *p;
p = &a;

要为指针的目标指定值,可以通过在指针名称前加*来取消引用它:

int a = 0;
int *p;
p = &a;
*p = 1;

答案 5 :(得分:1)

解除引用的指针是它指向的内存。只是不要混淆声明指针并使用它。

如果您在类型附近的声明中写*,可能会更容易理解:

int* p;

int some_int = 10;
int* p = &some_int; // the same as int *p; p = &some_int;
*p = 20; // actually does some_int = 20;

答案 6 :(得分:1)

分配和解除引用之间的区别是正确的。

您需要了解的是,您的数组变量是指向连续内存区域的第一个元素的指针

因此,您可以通过取消引用指针来访问第一个元素:

*(array + (n * sizeof(my_array_type)) ) = 10;

您可以通过取消引用指向第n个元素的指针来访问第n个元素:

array[n] = 10; 

其中地址是指向第一个元素的指针加上第n个元素的偏移量(使用此数组中元素的大小乘以n计算)。

您还可以使用等效语法访问第n个元素:

mydata<- read.csv("q.csv")
# K-Means Cluster Analysis
fit <- kmeans(mydata, 3) # 3 cluster solution
# get cluster means
abc<-aggregate(mydata,by=list(fit$cluster),FUN=mean)
abc[1]
# append cluster assignment
mydata <- data.frame(mydata, fit$cluster) 
mydata