为什么在C语言中要使用指针?

24

我仍然想知道为什么在C语言中,你不能简单地使用普通变量将一个东西设置为另一个东西。变量本身不是指向数据的指针吗?那么为什么要使指针指向变量中的数据,而不直接使用原始变量呢?这是为了访问变量中特定的位(或字节)数据吗?

我相信这很合理,但我从未完全掌握这个概念,当阅读代码时看到*pointers总是让我感到困惑。


1
学习时,我发现更容易记住指针只是保存内存地址的变量,无论看起来多么复杂。因此,char ***p 看起来很可怕,但最终它只是保存单个内存地址的变量。 - teppic
11
如果“原始变量”是一个10MB的网络缓冲区,你打算如何将其传递到函数中?复制它吗?如果要将其排入另一个线程的队列中,该怎么办?需要复制两次吗? - Martin James
@MartinJames 不错的提示。 - Gewure
4个回答

35

指针通常有助于编写函数。函数按“按值传递”的方式获取其参数,这意味着它们获取传入内容的副本,如果函数将新值分配给其参数之一,则不会影响调用方。这意味着您无法像这样编写“加倍”函数:

void doubling(int x)
{
    x = x * 2;
}
这是有道理的,因为如果您这样调用加倍函数,程序会怎么做呢:

这是有道理的,因为否则如果你像这样调用doubling函数:

doubling(5);

指针提供了解决这个问题的工具,因为它们可以让你编写接受变量地址的函数,例如:

void doubling2(int *x)
{
    (*x) = (*x) * 2; 
}

上述函数的参数为一个整数地址。函数体内的一行代码对该地址进行两次解引用:在等号左边我们将其值存入该地址,在右边我们获取该地址的整数值并乘以2。最终结果是该地址处的值被加倍。

顺便提一句,当我们想要调用这个新函数时,不能传入一个字面值(例如 doubling2(5)),因为它不会编译通过,我们没有正确地给函数传递地址。一种给它传递地址的方式如下:

int a = 5;
doubling2(&a);

最终结果是,变量a将包含10。


2
我最喜欢这个答案。它很直接,示例也是简约而非常好的。 - Gewure
一如既往,做事的最佳方式就是自己动手。我测试了这个脚本并且理解得很好。 - Alejandro
这真的很有道理。非常感谢你。 - Kaneda

20

一个变量本身就是指向数据的指针。

不,它不是。一个变量代表一个对象,即一个左值。左值的概念与指针的概念根本不同。您似乎混淆了两者。

在C语言中,无法重新绑定左值以使其“指向”内存中的另一个位置。左值和它们的内存位置之间的绑定在编译时确定且固定。它并不总是100%特定(例如,局部变量的绝对位置在编译时未知),但足够特定,使其在运行时不可由用户调整。

指针的整个概念是,其值通常在运行时确定,并可以在运行时指向不同的内存位置。


一个左值可以被重新绑定,例如如果p是一个指针,那么*p是一个左值,通过改变p的值可以使其引用不同的对象。当你说“左值”时,你的意思是命名对象 - M.M

11
不,变量不是数据的指针。如果使用“int x,y;”声明两个整数,则无法使x和y引用同一内容;它们是分开的。
每当读取或写入变量时,计算机必须以某种方式确定该变量在计算机内存中的确切位置。计算机将查看您编写的代码并使用它来确定变量的位置。指针可以表示编译代码时位置未知的情况;只有在实际运行代码时才会计算出确切地址。
如果不允许使用指针或数组,那么您编写的每一行代码都必须访问在编译时就已知的特定变量。您无法编写一个通用的代码片段,从由调用者指定的内存中读取和写入不同的位置。
注意:还可以使用带有变量索引的数组来访问地址在编译时未知的变量,但是数组大多只是指针的语法糖。您可以考虑所有数组操作而不是指针操作。数组不如指针灵活。
另一个注意事项:正如AnT所指出的那样,局部变量的位置通常位于堆栈上,因此它们是一种位置在编译时不知道的变量类型。但是,堆栈之所以适合存储可重入函数中的局部变量,是因为编译器实现了称为堆栈指针和/或帧指针的隐藏指针,函数使用这些指针来查找哪个内存部分保存它们的参数和局部变量。指针非常有用,以至于编译器在不告知您的情况下背后使用它们。

5
另一个原因是:C语言设计用于构建操作系统和大量处理硬件的低级代码。每个硬件都通过寄存器公开其接口,并且在几乎所有体系结构中,寄存器都映射到CPU内存空间中,并且它们不必始终位于相同的地址(由于跳线设置、PnP、自动配置等)。因此,在编写驱动程序时,操作系统编写者需要一种处理看起来像内存位置的方式,只是它们不引用RAM单元。
指针用于此目的,允许操作系统编写者指定要访问的内存位置。

几乎所有的架构……除了最常用的那个 ;) - m0skit0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接