你好, 欢迎回来｡ 在这节课里我想谈谈点算术｡
现在我们了解了数组和指针之间的关系, 这个概念将更容易理解｡
我们说算术, 但实际上并不是,
它的真正含义是你可以对指针本身进行加,
减, 增, 减操作.
因此, 当您要对数组元素进行排序时,
使用指向数组的指针的真实的功能就发挥了作用｡
你想从第一个元素到最后一个元素, 你想遍历它们｡
这才是真实的的力量指针｡
因为指针指向使用地址, 所以数组中每个元素只是另一个地址
所以你可以在指针上做加法, 然后你就可以去到下一个地址｡
所以这里的值指针可以用来访问值数组的第一个整数｡
它可用于访问小于0的值｡
如果你还记得值指针是一个指向整型数组的指针｡
我们把它赋值给数组中的第一个元素, 方法是把指针赋值给数组名.
如果需要, 我们也可以使用操作符sub-0的地址｡
但是当我们解引用值指针时因为它指向数组中的第一个元素, 它会给予你值为sub-0的数组中的第一个整数.
如果你想通过指针变量引用value sub 3, 你所要做的就是在values指针上加3,
然后应用间接操作符来取消引用它｡
所以你可以这样做｡ 你可以说values pointer加3,
然后用星号取消引用它｡
你通常把星号放在引号外面, 以使它清楚｡
但它所做的是,
值指针, 它是数组中第一个元素的地址, 它会加3.
所以它实际上会把整数的每个字节相加, 它会把字节乘以整数｡
但实际上它指向的是sub 3,
数组中的第四个元素.
所以在表达式中,
星号值指针加上i, 可以用来访问值数组中包含的任何值｡
如果你理解这个表达式, 你可以在i上加任何东西,
它会指向一个特定的元素数组.
所以如果你想把value sub 10设置为27,
你所要做的就是,
如果你使用的是一个指针, 比如说value指针加10, 然后解引用它, 等于27.
所以你可以看到这里的不同语法｡
同样, 这是符号上的方便, 但就程序本身而言, 它也更有效｡
指针因为和数组关系密切, 你可以很容易地访问元素,
只需要增加指针, 减少指针,
或者从指针中加上或减去值.
非常非常有用｡
若要将值指针设置为指向值数组的第二个元素,
可以将地址运算符应用于值sub 1, 并将结果赋给值指针｡
我们看到了｡
如果你想使用地址子运算符, 这只是我前面提到的另一种方法｡
如果你愿意,
你可以随时这样做, 但是做指针运算要方便得多｡
如果值指针指向值sub-0, 则可以通过简单地将值指针的值加1来将值指针的值设置为1｡
这就是我们用点运算得到的结果｡
你所要做的就是说values
point或者plus equals one, 现在values指针指向数组中的第二个元素或者第一个索引｡
非常非常好的符号, 非常容易做｡
所以这是一个非常有效的表达式,
可以用于任何数据类型的指针, 无论是整型字符还是其他类型｡
你也许应该考虑一下这在角色中有多有用｡
如果你有一个字符指针,
你现在可以访问字符串中的每个元素, 每个字符, 只需要在指针上加一个加号｡
在处理这些指针时, 增量和减量运算符plus
plus和minus
minus特别有用, 因为您通常希望从一个元素转到下一个元素, 依此类推｡
加22或减20并不常见, 因为你通常是按顺序来的｡
因此, 在指标中使用递增运算子与在指标上加一的效果相同｡
使用递减运算符与从指针中减去一具有相同的效果｡
所以说plus
+ values指针会设置values指针指向values数组中的下一个整数｡
减,
减应该是值指针, 它将把值指针指向值数组中的前一个整数｡
但是在做减法的时候要小心因为你要确保你至少在数组中并且不在0.
对plus plus来说也是一样｡
如果你在数组的末尾, 你不希望有任何越界错误｡
所以要确保值指针,
如果你在递减它, 它一开始并没有指向值数组的开头.
另一个例子, 我们要对数组中的所有元素求和,
你可以看到我们有一个数组求和函数, 这个函数接受一个数组,
同时也接受一个常量整数作为参数.
在函数内部, 我们要创建一个整数.
我们要把整数和初始化为0, 然后创建一个整型指针, 一个指向int类型的指针.
我们还要创建一个常量指针｡
所以这意味着你不能改变它的地址｡
它总是数组加n, 它被命名为数组结尾.
我们这样做是因为如果我们把循环设置为, 到数组末尾, 只看指针,
会使循环更有效率｡
所以array end是指向数组末尾的地址｡
我们可以说数组, 也就是传入的数组n是数组的大小.
现在for循环将初始化循环控制变量指针, 它是指向数组的指针｡
你要做的就是, 如果你想给数组的第一个元素赋一个指针, 你要做的就是说指针等于数组.
然后我们的循环退出条件是如果指针小于数组结尾｡
请记住, 指针是地址, 数组结尾也是地址｡
所以我们说如果地址at指针小于指针n, 那么我们要执行循环体｡
指针只是一个整数, 它是一个十六进制地址｡
每次递增时, 它都会转到下一个地址｡ 我们有结束地址,
所以我们可以说遍历循环, 直到到达结尾｡
然后我们递增指针本身,
它会递增地址, 指向数组中的下一个元素, 因为这就是我们要指向的东西｡
然后在循环体中, 我们说sum plus equals指针.
我们通过解引用指针来获取值, 因为记住我们要获取的是值, 而不是指针的地址,
或者指针指向的地址.
最后, 我们返回总和｡
这是对数组中所有元素的求和｡
你会注意到, 我们还在这里声明了函数,
而不是在文件的顶部. 我通常喜欢把它们放在文件的顶部｡
但总的来说, 我们创建了一个10个元素的数组, 37-9等等｡
然后我们传入数组或总和, 并将大小指定为10｡
你会注意到它返回的值是数组的和.
所以用这种点算法来迭代数组是非常非常好的,
我们可以加到下一个地址, 也可以看结束地址来跳出来｡
与计数器查看小于n的地址相比, 指针查看结束地址的效率更高｡
你也会注意到我们把它们创建为常量, 因为常量不会改变,
这对编译器来说更有效.
这里的数组是一个常量指针, 意味着地址不能改变｡
您还应该注意到,
在本例中, 要将数组传递给函数, 只需指定数组的名称｡
所以我们知道如何传递raise函数｡ 而要产生指向数组的指针,
只需要指定数组的名称｡
当我们将数组的第一个元素赋值给指针时, 我们看到了这一点｡
这意味着,
调用数组求和函数时, 传递给函数的, 实际上是指向数组值的指针｡
这实际上是告诉你数组和指针是非常非常紧密的联系, 数组只不过是一个指针.
这就解释了为什么你可以在函数中改变数组的元素.
因为直到现在, 当你把数据传递给函数时, 除非它是一个指针,
否则数据不会在函数之外被改变｡
因为这就是为什么我们必须为scanf传递地址｡
元素在函数外被改变的唯一方式是你将指针传递给函数｡
因为元素在函数内部被修改, 这意味着你传递的是一个指针｡
这再次证明了数组和指针是非常非常相似的, 因为数组实际上是指针, 只是使用了不同的语法｡
我们将讨论如何通过引用传递,
或者传递引用的副本, 这将允许你在函数外修改函数中的数据.
如果你还记得我们之前的一个挑战, 每当我们想改变一个函数中的数据, 我们必须使用一个全局变量｡
因为我们不理解通过引用传递的概念, 也不理解指针的概念｡
但是我之前也提到过指针的一个优点是你可以在函数内部改变数据, 并且它会在函数外部得到反映｡
但那是另一个讲座｡
但是这个概念本身, 因为前面的例子,
演示了数组本质上是指针｡
因此, 您可能想知道为什么函数中的形参没有声明为指针｡
嗯, 有可能｡ 我们可以这样做, 整型数组, 求和, 整型, 星星数组.
我们不需要将其声明为数组｡
它是完全有效的, 因为数组和指针是一样的, 我们可以说int, 星星, array｡
我们提到过它们之间的关系非常密切｡
所以你可以声明一个数组类型,
是一个int数组类型, 在数组求和函数中, 或者你可以把它声明为一个指向int的指针.
这就是为什么你会看到很多函数接受数组作为参数, 或者作为实参,
其中的参数实际上是指针｡
所以如果你要使用索引号来引用传递给函数的数组元素, 那么就把参数声明为数组.
再一次为了方便起见,
它只是一种不同的表示方法, 或者使用括号和下标, 或者使用指针｡
数组本身通常在程序维护方面更容易读取, 它更正确地反映了函数对数组的使用｡
但是指针更容易使用｡
如果你使用一个参数作为指向数组的指针, 那么在形参中声明它是指针类型｡
这里有一个函数的指针表示法的例子, 而前面的例子使用的是数组表示法｡
这里我们只说int, start,
array, 你会注意到函数马上变小了很多, 因为我们不需要像之前那样, 把数组的指针赋给第一个元素.
循环也变得更小了, 因为我们不需要在第一条语句中进行赋值｡
我们可以说, 直到数组小于数组结尾, 我们可以递增数组.
所以代码少了一点, 如果你理解数组和指针的话, 它还是很清楚的｡
我们传递的是int, 星星数组, 我们不再需要初始化这个数组因为我们传递的是指针,
我们不再初始化指针.
然后我们实际上把数组结尾的地址设置为一个常量指针, 数组结尾.
我们用它跳出循环, 我们只需要说sum
plus equals, 星星array, 用间接操作符再次解引用数组, 返回和.
然后main函数是完全相同的, 除了声明现在是一个指针而不是数组｡
这里有两个使用不同符号但提供相同功能的例子, 这就是为什么你会看到很多指针作为函数参数中的参数｡
所以这里总结一下, 当你使用指针的时候, 有些东西是有效的,
有些东西是无效的｡
所以如果我们在这里声明一些变量, 我们声明一个名为earn的数组, 它包含3个元素,
然后我们声明2个指针｡
现在我们可以用这些指针来做算术｡ 我们可以说指针1 ++｡
我们可以说点或2等于点或1加2｡
我们甚至可以说指针2等于earn加1｡
这样做是完全有效的, 因为你有指针, 你通过地址来修改指针,
所以你可以做点运算.
你不能在数组上做点运算｡ 所以你不能说赚加加｡
您不能说指针2 0 2加0｡
1, 因为这些是地址｡
实际上你并没有指向数组中的任何东西｡
而且您不能将积分或1乘以积分或2｡
这些都是无效的｡
因此,
请注意指针运算的正确语法, 还要理解指针运算只能应用于指针, 而不能应用于数组｡
处理数组的函数实际上也使用指针作为参数｡
您可以在数组表示法和指针表示法之间进行选择, 以编写数组处理函数｡
所以如果你要处理随机函数, 用指针作为参数是完全可以的｡
您可以选择要使用哪一个｡
但使用指针通常代码更少, 效率更高｡
使用数组表示法可以更明显地表明函数是使用数组的,
并且对于具有某些语言编程背景的程序员来说, 数组表示法看起来更熟悉｡
所以如果你在Fortran和Pascal等之前编程, 你可以使用箭头符号｡
其他程序员可能更习惯于使用指针, 可能会发现指针表示法更自然,
更有意义｡
它更接近于机器语言,
使用点运算和指针符号与一些编译器, 它导致更有效的代码, 另一个原因, 使用它｡
让我们来看看代码块中的这些示例｡
这是幻灯片中的示例｡ 我们在第3行有函数声明｡
这是一个数组和｡
在这个例子中, 我们将使用数组表示法｡
所以我们在使用索引时要用到括号｡
我们将调用它传入值数组和大小｡
所以数组求和函数采用整数数组｡
首先你要做的是创建一个指针, 用来在第14行进行点运算.
然后你必须把数组的结尾赋给地址数组加上大小｡
这是数组的结尾, 现在可以用它来退出循环｡
但是我们必须将指针赋给数组｡
我们知道,
我们可以通过数组的名字, 将数组赋值给指向第一个元素的指针｡
我们不必用特工的地址｡
如果我们想的话, 我们可以做这样的事情｡
这个也很好｡
然后我们加上指针｡
我们增加指针是因为所有的操作都是增加到下一个地址｡ 它指向数组中的下一个元素｡
然后在第18行, 我们解引用指针来计算和, 和等于,
和加上它所指向的指针的值｡
所以如果我们构建这个函数, 我们会有一个警告, 那就是main不是int,
我们想改变这个,
因为从main返回错误值, 然后说return 0就行了.
如果main中有错误, 你可以返回一个负的值｡
现在我们运行这个程序, 你会看到它只是对数组中的值求和, 也就是3加7加-9等等,
甚至不确定是多少, 但看起来是21｡
现在,
我们可以很容易地修改这个数组参数, 通过在指针前声明星号来获取指针｡
我们也这么叫｡ 我们只是修改｡ 我们不再需要声明指针｡
我们可能需要更改名称以使其更简单, 但我们不再需要声明此指针｡
我们仍然想得到数组的结尾, 也不需要再赋值了.
我们可以在那里放个空的｡ 在这里使用while循环可能会更有用｡
但是如果我们没有赋值, 我们可以把分号放在那里｡
现在我们没事了｡ 我们仍然希望取消引用它, 并且仍然希望返回它｡
但是如果我们构建了这个函数,
我们需要确保我们将函数声明定义为一个指针, 因为我们修改了它｡
这可以是任何名字, 但我们要保持一致｡
现在我们构建, 我们要确保我们再次使用了所有改变过的变量｡
现在我们成功地构建了, 我们运行它, 你会看到你得到了相同的结果,
也就是21｡
因此, 理解在数组中使用指针作为形参之间的区别, 就可以互换使用它们｡
这只是一个符号上的方便｡
但是当你使用指针的时候, 你通常有更少的代码｡
你可以对它进行更多的操作, 你可以做更强大的事情,
它通常也会更有效地基于编译器｡ -谢谢—谢谢