当我学习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:谢谢你们帮助了我很多的人!
答案 0 :(得分:3)
我不知道你什么时候使用*当你使用指针而不是。携带十六进制的所有东西都是指针对吗?数组的变量名称带有十六进制内存位置。那么为什么它不是指针?
最后一件事 - 数组的名称是而不是指针;它不会在任何地方存储地址。定义数组时,它的布局或多或少如下:
+---+ arr: | | arr[0] Increasing address +---+ | | | arr[1] | +---+ | ... | +---+ | | | arr[n-1] V +---+
对于与数组元素arr
到arr[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