你好, 欢迎回来｡
在这节课中, 我想讲一个概念, 叫做通过引用传递｡
当我们第一次开始讨论指针的时候, 我提到了它的一个优点,
那就是你不需要使用太多的全局变量｡
因为当你传递一个指针给一个函数时, 函数就可以使用那个参数｡
而当它修改该参数时, 数据将在函数之外被修改｡
所以这是一个很有价值的概念｡
我们得好好谈谈｡ 这更多的是一个概念｡ C实际上并不使用这个｡
我将向你们展示这是如何实现的, 并给予你们一些基本上是如何实现的例子｡
这就是按值传递的概念｡ 这与功能有关｡
我们讨论了如何将数据传递给函数, 但实际上是如何在编译器的语言中传递数据的｡
所以有一个按值传递的概念｡
这就是我们一直在讨论的｡
每当我们调用scanf函数之外的函数时, 但每次调用该函数时,
当你修改函数内的数据时, 它不会在函数外被修改｡
我们讨论了局部变量, 这是一个不同的概念｡
但是, 当您将数据传递给函数时, 有两种方法可以传递它｡
可以通过值传递, 也可以通过引用传递｡
C和java都是通过值进行传递的｡
但是它模拟了通过引用传递, 因为您复制了地址｡
因此,
尽管c语言没有特别使用这个通过引用传递的概念, 但它模拟了它｡
为了理解引用传递的含义以及它的重要性, 我们将讨论它｡
但传值传递是指函数将参数的实际值复制到函数的形参中｡
这就是为什么如果你有一个整型,
浮点型或者双精度型, 你把它作为参数传递给一个函数,
实际的变量在函数外不会被修改, 因为它是被复制的｡
因此, 对函数内参数所做的更改不会影响参数｡
传入的参数未被修改｡
所以它的作用就像一个局部变量因为它是一个副本.
它实际上是如何被复制并传递给函数的｡
C程序使用传值调用来传递参数｡
一切都是按值调用按值传递的｡
这些术语可互换使用｡
因此, 这再次意味着函数中的代码不能更改用于调用函数的参数｡
虽然这些值在函数内部已被更改, 但它们没有更改｡
看起来它们是局部变量｡
这就是为什么在此之前, 如果要在函数之间共享数据, 必须创建全局数据｡
这就是c的工作原理｡
但是当你实际传递一个地址的副本时会发生什么｡
然后, 它可以模拟通过引用传递｡
但是这里有一个例子, 我们是如何使用传值的, 它在这里演示得很好｡
这个swap例程是演示传值传递的一个常用案例,
因为它所做的是创建一个temp, 并交换正在传递的参数｡
如果我们有一个名为swap的函数, 它接受两个整数,
我们创建一个局部变量temp｡
如果我们把参数x赋给temp, temp就等于x.
如果我们说x等于y, 那么y现在就等于x｡ 如果我们说y等于temp, 那么y就等于temp｡
但是当调用这个函数传递这些值的时候, x和y对于这个函数来说是局部的｡
这些变量不会在此函数之外被修改｡
这个函数非常有用, 因为我们给y赋值,
给x赋值.
x和y是函数的局部变量,
因为我们是传值的, 它们在函数外不会被修改, 这就是为什么我们要用全局变量.
但它们是整数｡ 它们是两个整数x和y｡ 它们不是地址,
而是整数, 这很重要｡
如果我们调用swap, 看到的是什么样子, 你会注意到值没有改变｡
所以如果我们创建一个变量,
名为100b, 其中有200, 我们在交换之前打印出变量,
100和200, 然后我们调用交换, 变量在我们再次打印出来之后不会改变｡
让我们在代码块中看看这个, 这将演示按值传递｡
这是我们的例子｡ 我们有我们的交换程序｡
我们在交换传递给x和y的数据的值｡
我跟100 200｡
在调用函数之前我们要打印出来｡
之后我们会打印出来｡
你会注意到变量a和b是不变的｡
原因是因为我们是按值传递的｡
如果我运行这个程序, 我们可以看到在交换之前a的值是100, 在交换之后a的值是100, b的值是200和200｡
这是因为我们是按值传递的｡
如果我们通过引用传递, 则变量a和b在调用swap后会发生变化｡
现在, 如果我们使用同样的技术, 通过值传递,
但是我们复制指针, 你认为会发生什么？
所以指针和函数可以沿着地结合在一起｡
您可以将指针作为参数传递给函数, 也可以让函数返回指针作为其结果｡
我们也将展示如何做到这一点｡
但是通过引用传递将参数的地址复制到形参中｡
该地址用于访问调用中使用的实际参数｡
所以这意味着对函数中参数的改变会影响调用中的参数.
因此, 尽管从技术上讲, 它并不是通过引用传递的,
但它模仿或模拟了通过引用传递｡
我们正在复制地址｡
如果复制地址, 则会有一个新的地址和存储该地址值的内存｡
但是如果你试图赋值给那个地址, 它就会赋值给那个地址｡
所以即使它是按值传递的, 它也是复制的｡
如果你复制的是一个普通的整数, 你不需要做任何改变｡ 如果你复制一个地址,
这个地址在内存中, 所以当你做改变的时候, 你要对这个地址做改变｡
因此, 要通过引用传递值, 参数指针将像传递任何其他值一样传递给函数｡
您需要将函数参数声明为带星号的指针类型｡
函数内部的更改也会反映到函数外部｡
您不必经常使用全局变量｡
与传值调用不同, 在传值调用中, 更改不会反映到函数外部｡
我们仍然在复制, 我们仍然在传递值, 它只是地址副本的值｡
所以这是一个需要理解重要概念
当我们创建swap函数时, 我们要在函数中声明星号, 星号和星号.
也就是说这个函数接受指针｡
现在当我们在这个函数中赋值时,
我们必须使用间接操作符来解引用, 因为我们要赋值｡
我们要把x指向的值赋给temp.
我们要把x指向的值赋给y指向的值, 然后我们要把y指向的值赋给temp｡
Temp是一个整数, 所以我们不必解引用它｡
现在, 当我们通过传入a和b,
用a100和b200调用它时, a和b不是指针, 所以我们必须传入地址,
因为函数接受指针｡
当你有一个接受指针的函数而你没有声明指针时,
你必须使用运算符的地址, 这和我们使用scanf是一样的｡
但是现在你会注意到,
当我们在调用交换变量之后调用这个函数时, 变量a和b会被改变, 它们会被交换｡
A是200, b是100｡
现在, 让我们看看这个示例, 其中swap方法更改为代码块中的指针｡
我们在代码块中｡ 我们修改了swap函数以获取指针｡
所以我们在赋值的时候必须解引用它们｡
我们现在也传入a和b的地址, 因为它们现在是整数, 交换现在接受指针｡
运行此程序时, 我们将看到call和after现在将发生更改｡
所以在我们调用swap之前a等于100在我们调用swap之后是200｡
在我们调用b的swap之前, 它是200｡ 之后, 是100｡
所以我们可以改变函数中变量的值因为我们复制了地址.
非常非常重要, 也是指针的一大优势｡
让我们总结一下语法｡ 我已经做了, 但让我们来更详细地介绍一下｡
您可以将有关变量的两种信息传递给函数｡
您可以传输x的值, 并且必须使用与x相同的类型声明函数｡
我们都知道｡
当我们传递数据给函数时, 调用它时必须具有相同的类型｡
这里我们用int function1来调用它它被定义为一个int num.
所以当我们在函数中传递x的值时, 它们必须声明为相同的类型｡
然后如果你想真正调用一个x地址,
它需要函数定义包含一个指向正确类型的指针｡
所以每当你使用指针的时候,
你必须确保如果你传入的数据不是指针, 你必须得到它的地址｡
总结一下, 如果你定义了一个不接受指针的函数,
你可以直接调用它并传入数据.
确保它不是指针｡
如果你有一个接受星号指针的函数, 当你调用它时,
你必须用add或sub操作符来调用它｡
你得把地址传进去｡
这就是语法｡
现在, 您也可以使用constant保留字来限定函式参数｡
这表示函数会将为此参数传入的参数视为常数｡
仅当参数是指针时才有用｡
因为如果你传递的是值, 而不是指针, 这并不重要,
因为它不会影响函数外部的变化,
所以为什么要把它设为常量呢, 谁在乎你是否改变它呢.
你把指针设为常量的唯一原因是因为你不想让函数外的值发生变化｡
因此,
您可以将constant关键字应用于作为指针的参数, 以指定函数不会更改参数所指向的值｡
非常重要的｡
因此, 在本例中, 我们有一个发送消息函数｡ 它接受一个p消息指针｡
我们将常量关键字放在char星星之前｡
所以这种类型的参数p message是一个指向常量字符的指针｡
常量是字符值, 而不是其地址｡
所以在这个例子中我们所做的是, 被指向的指针不能改变｡
我们可以改变地址, 但不能改变它指向的值｡
语法类似于我们在其他指针上创建常量时的语法｡
常量关键字是它首先显示的, 然后你不能改变它的值｡
现在你可以指定指针本身是常量,
但是这没有什么意义, 因为地址是通过值传递的｡
您无法变更呼叫函式中的转译指标｡
如果你想让它的地址不能被改变, 这有什么意义因为它是按值传递的. 所以你实际上是在创建一个新的内存位置来保存那个特定的地址｡
所以如果你改变它, 谁在乎它不会改变它的外表｡
你只想让参数成为一个常量这样你就不会改变它所指向的值, 你也不能改变原始指针和调用函数因为它是通过复制传递的值来传递的.
编译器知道, 指向常量数据的指针参数是安全的,
因此这样做有很多好处｡ 您不会意外地修改值所指向的内容｡
所以如果你不想改变反映在函数的外部, 你可以再做一次.
如果您将指向常量数据的指针作为参数的实参传递, 则必须像上面那样使用该参数｡
当你调用函数并将其传递给常量时,
你必须让函数声明也接受一个常量字符指针, 就像其他常量指针一样｡
它们必须被定义, 并且定义必须与原型匹配｡
从函数返回指针｡
从函数返回指针是一种特别强大的功能｡
它提供了一种不仅返回单个值, 而且返回整个值集的方法｡
所以我提到的指针的另一个优点是你可以从函数中返回更多的数据｡
在过去, 您只能传回一个值｡
但是有了指针, 因为指针可以指向一个我们还没讲过的结构, 或者其他的东西, 你可以返回多个值,
我们已经知道如何把指针传递给函数了, 现在我们来谈谈返回指针的问题.
你必须声明一个返回指针的函数｡ 所以函数声明必须匹配｡
这很容易做到｡
当你声明函数或者定义函数的时候, 你只需要用星号, 并且让指针的返回类型是它所指向的｡
因此, 尽管返回指针存在特定的危险, 但还是要小心｡
使用局部变量可避免干扰参数所指向的变量｡
当你返回指针的时候,
会有一些问题因为如果你在函数中修改了指针, 然后返回它, 这可能是你不想让它做的事情.
因此, 如果不想影响参数指向的变量, 请始终使用局部变量｡
所以这节课讲了如何传递指针给函数, 以及如何从函数返回指针｡
通过使用这种向函数传递指针的机制,
它演示或模拟了通过引用传递, 因为你在复制一个地址｡
当你复制一个地址的时候如果你写了这个地址,
你会更新指向这个地址的任何东西, 这实际上意味着你在改变函数内部的数据值, 它会反映在函数外部｡
我们使用交换例程来演示这一点｡
这是一个非常强大的概念｡ 如果你想模仿引用传递,
你可以用指针来做, 当你想改变函数外的东西时, 你就想这么做｡
-谢谢—谢谢