我开始学习C。
现在,根据我的理解,指针用于指向另一个变量的地址,并通过不直接接近它来改变该变量值。
现在,我有3个问题:
这是对的吗?如果是这样,我为什么需要它呢?
还有其他用途吗?
以下代码行之间是否有任何区别:
// 1
int x = 10;
int *ptr = &x;
// 2
int x = 10;
int ptr = &x;
答案 0 :(得分:2)
指针的值是内存中另一个对象的位置。所以给出第一组声明:
int x = 10;
int *ptr = &x;
你在内存中有类似的东西(地址是凭空而来的,并不代表任何真正的平台):
Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- x 0x08001000 0x00 0x00 0x00 0x0A ptr 0x08001004 0x08 0x00 0x10 0x00
x
包含值10
。 ptr
包含x
的地址。因此,表达式 x
和*ptr
是等效的;阅读或写入*ptr
与阅读或写入x
相同。
FWIW,它和
之间的区别int x = 10;
int ptr = &x;
是ptr
被视为整数,而不是指向整数的指针,因此如果您尝试*ptr
(一元*
的操作数),编译器将会牦牛必须是指针类型)。
那么,为什么指针?
C中的指针用于3个目的:
首先,指针允许我们模仿传递引用语义。在C中,所有函数参数都按值传递;这意味着函数的形式参数是内存中与实际参数不同的对象。例如,使用此swap
函数:
void swap(int a, int b)
{
int t = a;
a = b;
b = t;
}
int main(void)
{
int x = 1, y = 2;
swap(x, y);
...
}
如果我们看一下记忆,我们会有如下内容:
Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- x 0x08001000 0x00 0x00 0x00 0x01 y 0x08001004 0x00 0x00 0x00 0x02 a 0x08001010 0x00 0x00 0x00 0x01 b 0x08001014 0x00 0x00 0x00 0x02
这意味着对a
和b
所做的任何更改都不会反映在x
或y
中;致电swap
后,x
和y
将保持不变。
但是,如果我们将指针传递给x
和y
传递给swap
,就像这样:
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
int main(void)
{
int x = 1, y = 2;
swap(&x, &y);
...
}
然后我们的记忆看起来像这样:
Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- x 0x08001000 0x00 0x00 0x00 0x01 y 0x08001004 0x00 0x00 0x00 0x02 a 0x08001010 0x08 0x00 0x10 0x00 b 0x08001014 0x08 0x00 0x10 0x04
a
和b
包含x
和y
的地址,因此从表达式读取和写入 *a
和*b
相当于x
和y
的阅读和写作。因此,在此调用swap
后,x
和y
的值将会更改。
我们使用指针的第二个原因是跟踪动态分配的内存。当我们想在运行时创建一个新对象时,我们使用malloc
或calloc
调用,它分配内存并返回指向它的指针:
int *p = malloc(sizeof *p * N); // dynamically allocates enough memory
// to hold N integer values and saves
// the location to p
指针是用于跟踪C中动态分配的内存的唯一方式。
最后,指针允许我们创建动态数据结构,例如列表,树,队列等。想法是结构中的每个元素显式指向下一个元素。例如,这是一个定义简单整数列表的类型:
struct elem
{
int data;
struct elem *next;
};
struct elem
类型的每个对象都明确指向以下struct elem
类型的项目。这允许我们根据需要在列表中添加项目或从列表中删除它们(与数组不同),它允许我们在构建时对列表进行排序(我发布了一个示例,但我很累,可能没有意义;无论如何,你很快就会到达他们身边)。
答案 1 :(得分:1)
指针存储给定类型的内存地址。 &x
是变量x
的地址,该变量目前存储值10. int* ptr
可以保存此位置。改变10(又名x
)你可以说
*ptr = 3;
您的第二个代码块将地址存储在ptr
中,就好像它是一个实际数字一样。这意味着当您尝试打印ptr
时,您会注意到它是一个半随机数(可能非常高)。
我建议你研究一下这些基本数据类型是如何存储在内存中的。
至于用途,您可以创建能够在其范围之外更改内存而不是为自己制作本地副本的函数。如果你继续学习并开始学习,应该更好地解释。你用什么学习C?我强烈建议放弃你所拥有的并获得K& R.
答案 2 :(得分:1)
指针通常用于存储变量的地址。在第一种情况下,&x
提供地址x
,变量*ptr
的值存储位于ptr
指向的地址值所指向的位置。在第二种情况下,ptr存储变量x的地址。
#include<stdio.h>
#include<inttypes.h>
int main()
{
int x = 10;
int *ptr = &x;
uintptr_t p = (uintptr_t)&x;
printf("x=%d ,*ptr=%d,ptr=%p,p=%p",x,*ptr,ptr,p);
return 0;
}
在我的机器上,此代码生成:
x=10 ,*ptr=10,ptr=0028FF14,p=0028FF14
答案 3 :(得分:1)
指针是一个内存地址,右边。
但它并不一定指向一个变量 想象一下:
int * x = malloc( 2 * sizeof( int ) );
这里有一个指向可以包含2个整数的内存区域的指针 所以:
x[ 0 ]
是第一个int x[ 1 ]
是第二个int 取消引用时,您将在该示例中指定第一个:
*x = 0; // same as x[ 0 ] = 0
关于你的第三个问题,确实存在差异:
int x = 10;
int *ptr = &x; // As expected, ptr is now a pointer to x
int x = 10;
int ptr = &x; // Certainly not what you expect as ptr is not a pointer
在第二种情况下,将内存地址分配给整数。它不是指针,如果指针的长度与int不同(例如,在64位平台中),则会出现问题。
指针很好,因为你可以做算术。
int * x = malloc( 2 * sizeof( int ) );
int * x2 = x; // So we don't touch x, as we'll need to free it.
x2++; // Now x2 points to the second integer.
x2[ 0 ] = 0; // same as x[ 1 ] = 0;
增量基于指针类型完成。这通常是魔术开始的地方。
如果我们在短片大小为2的平台上,您可以想象以下内容:
short * x = malloc( 2 * sizeof( short ) );
char * x2 = ( char * )x;
当char
的大小为1时,您现在可以访问前一个短指针的每个字节(4个字节,因为我们分配了其中两个)。
所以:
x2[ 0 ] -> First short / First byte
x2[ 1 ] -> First short / Second byte
x2[ 2 ] -> Second short / First byte
x2[ 3 ] -> Second short / Second byte
最后,当你处理结构时,指针也很好,你需要将它们作为参数传递。
在这种情况下,使用指针将传递结构地址。否则,结构将需要在调用时复制,这根本没有效率。
void foo( struct x p ); // Structure data will be copied
void bar( struct x * p ); // Only the address will be passed, no data copied