你好, 欢迎回来｡
在这节课中, 我想谈谈指针和结构的用法, 以及它们之间的关系｡
我们可以让一个结构中的元素成为指针, 然后我们也可以让我们的结构本身成为指针｡
两个非常有用的概念｡
所以这里结构很重要, c允许两个结构指针｡
所以当我们创建一个类型结构的变量时, 我们可以把它创建成一个指针｡
指向结构的指针比结构本身更容易操作｡
这是一种符号化的东西,
让事情变得更简单, 也更有效率｡
在c语言的一些较老的实现中, 结构不能作为参数传递给函数,
但我们知道指针可以｡
所以这就是为什么你在声明一个结构的时候, 要把它当作指针的另一个原因, 因为这样你就可以把它作为参数传递给一个函数了｡
即使您可以将结构当做参数传递, 传递指标也会更有效率｡
我们知道这样更有效率｡
我们在过去已经讨论过如何通过重要的可以更有效｡
在这种情况下, 它甚至更有效率, 因为如果你传入一个完整的结构,
如果这个结构很大并且包含很多元素, 你就把结构中的所有元素复制到那个参数｡
如果你传递一个指针, 就复制地址.
所以指针作为结构化的参数就更重要了因为结构可能很大.
因此, 许多数据表示都使用结构, 其中包含指向其他结构的指针｡
你会在你所有的c程序结构中看到很多这样的指针, 因为我们提到的原因｡
在旧版本中, 你可以将它们作为参数来传递,
这也是更有效的, 因为我们通过传值来执行所有操作, 这比复制这个大型结构中的所有元素更有效｡
因此, 将结构声明为指针非常简单｡
当你把一个变量定义为一个strike指针时, 你只需要在数据类型后面使用星号｡
我们说结构是一种新的类型｡
在这种情况下, 我们曾经重要的日期结构｡
我们只需要struct date, 然后使用星号日期指针,
您可能会希望将其初始化为null.
因为记住, 当你说struct date pointer, date,
struct date, date,
pointer的时候, 它并没有为分配任何内存, 它会创建内存来存储实际的指针｡
它并不是在为里面的数据创建内存｡
所以你可以给这个日期点赋值, 或者给另一个结构体赋值, 或者给它分配一个内存,
或者用一些数据初始化它.
所以变量日期指针可以像其他指针一样赋值, 你可以用赋值语句把它设置成指向今天的日期,
如果我们已经声明了今天的日期｡
我们只需要使用&号来获取它的地址｡
所以我们创建一个普通的日期结构体, 它是今天的日期｡
这样就为三种元素创造了记忆｡
然后我们创建一个指针, 并将另一个日期的地址赋给它｡
很简单｡
我们已经对常规数据类型做了这样的处理, 对结构也没有什么不同｡
然后, 您可以间接访问日期指针所指向的数据结构的任何成员｡
所以我们需要这样做｡
如果你想访问日期指针结构的元素, 你必须先取消引用它｡
所以把它放在括号里可能会很有用, 这样就很简单了｡
你必须解引用日期指针来得到今天的日期指向的值, 它指向的今天的日期地址的值, 以便设置特定的值｡
所以你可以解引用它, 然后执行dotday等于21, 这样就把21赋给了你的日指针｡
上面的内容只是说, 无论今天的日期指向什么, 我们都要访问该值,
并将日期设置为21｡
在这种情况下, 括号是必需的,
因为点的优先级高于星号｡
如果你没有把括号放在里面,
它就搞砸了因为它会在把指针指向数据之前, 先把点放在里面.
因此, 它会尝试使用空指针访问数据｡
所以通过取消引用, 你得到了这个值｡
现在, 当我们使用结构体a指针时｡
如果我们想测试存储在日期指针所指向的日期结构中的月份值, 我们可以这样做｡
我们解引用指针, 放在括号中, 所以它优先于点,
然后我们说点月份等于12｡
这是完全有效的语法｡
但它有点笨重｡
所以c有它自己的语法, 所以你不需要去引用所有的东西,
然后把它放在结构的括号里｡
当你想访问结构所指向的内容时, 你不必用这种方法去引用它｡
在c中有一个特殊的操作符, 用于指针的结构, 它是破折号大于｡
它是一个破折号后面跟一个大于号｡
这样你就不用去引用指针了｡
所以不用在括号里加上星星x, 然后加上点y, 你可以直接说x,
dash, 大于y.
因为x是一个指针, 所以你不需要引用它, 只要你想访问结构中的元素,
不管你指向什么.
所以你会看到这个语法到处都是｡
你不会看到括号和d引用｡ 这是完全有效的, 但您键入了更多的字符｡
直接说x大于y效率更高｡
所以前面的if语句不是在括号里取消引用, 你要做的就是说如果日期指针大于月份｡
这有点直观, 因为破折号“大于”表示它指向某个东西｡
所以日期破折号大于月份｡
所以日期指针是一个指针, 这就是为什么你用破折号大于｡
如果这是一个嵌套的结构, 你需要在结构上加上一个大于的破折号然后在后面加上一个点来访问嵌套结构中的元素.
但是因为日指针是一个指针, 所以你必须使用破折号等于或破折号大于｡
这里有一个例子, 我们创建了一个日期结构体,
我们有三个元素, 然后我们创建了一个指针, 日期指针, 我们今天只创建了一个常规变量｡
我们把今天的地址赋给指针,
然后再赋给结构体的实际元素, 我们只要用大于号, 然后就可以打印出来了.
让我们在代码块中看看它是如何工作的｡
所以我把这个例子放在这里｡
通常,
当你定义结构时, 你会在函数之外定义它们, 因为这样你就可以在任何函数中使用它们｡
这有点像全球性的｡
但请记住, 当你定义结构时, 你实际上并没有创造任何记忆｡
因此, 您仍然将变量创建为局部变量或指针,
但实际的定义在函数之外｡
所以如果你想用它, 你可以在任何函数中使用它｡
在顶部, 我们创建了一个新的结构体, 类型为date或者name
to date, 它包含三个整数, 以分号结尾.
然后我们在main中创建几个变量｡
一个是一个普通的变量结构, 日期, 今天,
还有一个是指针. 我们知道它是一个指针, 因为它前面有一个星号｡
我们知道, 当你创建一个指针时,
它只会分配内存来存储那个指针的值的地址｡
所以我们必须给它分配一个地址, 就像我们今天用&号做的那样,
因为这实际上是创建一个内存报告｡
所以现在日期指针将指向今天的地址｡
然后我们就可以开始给它赋值了, 用这个破折号, a quot a大于a quot
a, 非常有用, 就像其他人一样, 用赋值运算符赋值.
当我们打印出来的时候, 你会注意到我们不需要取消引用它就可以打印出来｡
要打印出来, 我们可以直接写格式说明符的数据类型, 这里是, 高, 高, 高, 高,
高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高,
高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高,
高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高, 高
现在我们可以改变它, 它将是有效的｡
我们必须在括号里加上月份｡
无论哪种方式都可以, 但要习惯破折号, 然后更大, 因为它是更好的语法｡
现在, 当我们构建它时, 你会看到它打印出日期指针的值, 它们都设置为9,
25和2015｡
今天的日期是9月25日15. 它被格式化为以这种方式打印｡
很简单的事情｡
只要记住破折号大于, 这是指向结构体的指针的新语法｡
但其他一切都很正常｡
我们知道指针必须有存储地址,
所以我们知道要么分配动态内存, 要么给它一个现有的结构体｡
让我们回过头来讨论更多关于结构体和指针的内容｡
现在我们来讨论一下包含指针的结构｡
我们知道如何为结构创建指针｡
如果我们不想给一个已有的指针分配一个已有的地址, 我们可以为这个指针分配内存｡
但是你也可以在一个结构中有元素, 这个结构本身就是一个指针｡
因此, 指针也可以是结构的成员｡
我们不必使用字符数组｡
所以我们可以用struct, 我们可以用指针来命名它, 然后我们可以在这个例子中, 我们有两个整数,
两个整数指针p1和p2, 这是非常有效的语法｡
因此, 在指针中调用的结构被定义为包含两个整数指针｡
第一个称为p1, 第二个称为p2｡
你可以在指针中定义一个struct类型的变量, 就像normal, struct, int指针,
指针一样｡
现在可以像使用其他结构一样使用变量指针｡
指针不是指针｡
是整型指针｡
它包含两个元素在它的罢工是指针, 但指针本身不是一个实际的指针｡
所以要注意这点｡ 它是一个结构变量, 有两个指针作为它的成员, 这是不同的.
所以如果我们想访问指针变量中的元素, 我们不要用破折号, 因为指针不是指针,
它是一个结构体.
我们将使用点来访问p1和p2｡
所以在这个例子中, 我们创建了一个结构,
我们创建了一个变量｡ 它不是一个叫做指针的指针｡
然后我们创建两个整数,
i1等于100, i2没有初始化｡
现在p1和p2是指针｡
因此, 它们必须包含有效的内存地址, 其中这些地址已被内存分配｡
这就是i1和i2所做的｡
声明整数变量时, 会为这些整数分配内存｡
所以把地址i1和i2赋给p1和p2, 这是非常好的, 因为i1和i2有内存分配,
因为它们是整数｡
现在如果整数指针不是整数指针而是字符指针, 那么你就必须分配动态内存｡
现在我们只使用整数, 所以我们将两个整数的地址分配给p1和p2｡
我们现在可以说星星指针｡ p2等于97, 负97｡
为什么我们必须在那里取消引用它, 因为指针｡
p2是我们所引用的｡
指针｡ 点P2是指针｡
我们不是在访问一个结构的元素｡
我们正在取消引用所有指针｡ p2中｡
我们要把它赋值给指向-97的那个东西.
所以请注意这里的区别｡
我们不创建结构指针｡
我们正在创建一个常规变量指针, 但它包含两个指针元素｡
所以如果我们想给结构中的这两个元素赋值,
我们必须用间接操作符解除对它们的引用, 这就是我们在这里要做的.
然后在我们的两个打印报表中｡
同样,
我们要打印出p1所指向的值, 所以我们和p2一样, 取消对它的引用, 然后我们还要打印出指针所指向的值｡
所以在第一个例子中, 我们说i1等于百分比, I,
逗号指针｡ p1等于I百分比
所以双引号里的第一个字符只是打印出实际的文本,
它没有取消引用逗号后面的任何内容, 我们在这里取消引用｡
我们首先打印出i1, 它是100, 然后打印出指针p1,
它应该是100｡
在赋值给p2后, I2实际上是负的｡
那么字符数组或字符指针呢？ 在上一节课中,
我们讨论了如何创建一个字符数组, 作为指针中的一个元素｡
但是字符指针呢, 我们应该像first和last那样使用字符数组,
还是应该像first和last那样使用字符指针作为元素｡
有什么更好的选择｡
好吧, 我们走着瞧｡ 这实际上还是一个符号的问题, 但是使用指针有很多优点｡
所以当我们在元素中创建指向字符的指针时, 通常会更好一些｡
但是你需要理解这里是怎么回事当你创建数组元素char
array作为一个元素或者指针作为一个元素时, 两者都是有效的.
但两者有很大的区别｡
所以如果我们说结构体名veep或vp,
我们说Talia和Summers, 然后我们说结构体指针名｡
所以记住, 结构体名称包含字符数组｡
结构指针名称包含指针｡
我们在这里初始化指针等于布拉德和落颌｡
然后我们打印出第一个元素,
它是一个字符a和vp, 然后是treas的第一个元素, 它是指向first的指针｡
所以结构体将变量命名为veep｡
这里的情况是字符串存储在结构中｡
该结构总共分配了40个字节来保存这两个名称, 它们是字符数组｡
这就是在指针内部创建字符数组时所发生的事情｡
我们分配了40个字节来保存这两个名字, 20和20｡
对于指针名称变量treas, 无论我们是否有两个指针, 这些都是字符串,
存储在编译器存储字符串常量的地方｡
该结构保存这两个地址, 因为它们是指针｡
指针包含的值是地址｡
所以它要做的就是在这个结构中分配两个指针｡
对于大多数系统, 这是16个字节, 指针通常是8个字节或4个字节｡
struct p name结构不分配空间来存储字符串,
因为它只为指针本身分配空间｡
指针的值是地址｡
它指向的地址没有内存分配给它｡
所以当你创建这两个指针时, 没有为这两个指针分配内存｡
它不分配任何空间｡
因此, 它只能用于已在其他位置为其分配了空间的字符串｡
当你在一个结构中有指针时, 你必须使用malloc或calloc｡
否则, 它们可以存储在存储字符串常量的任何位置｡
这就是最大的区别｡
因此指针和p名称结构应该只用于管理在程序中其他地方创建和分配的字符串｡
您不希望将数据分配给它, 除非您已经动态分配了它, 或者已经在其他地方分配了它,
可能是通过现有的结构体或其他方式｡
但通常情况下, 你会想malloc这些指针｡
再次, 非常不同｡
在name结构体中为这两个字符数组分配40个字节｡
对于p name结构, 您有两个指针｡
当你创建一个这种类型的变量时, 没有为它分配内存｡
它只是为两个字符指针创建内存, 每个字符指针有8个字节｡
要为第一个和最后一个指向的对象实际分配内存, 必须执行malloc｡
因此,
在动态分配内存的情况下, 使用指针和结构来处理字符串是有意义的｡
这通常是您使用它的时候, 因为其他允许的数据类型会自动为您分配内存｡
所以你想用一个指针来存储地址｡
这样做的好处是, 您可以要求malloc只分配字符串所需的空间量｡
我们讨论了动态内存分配的优点｡
当您在编译时静态地创建内容时, 您将只创建特定数量的字节｡
如果你需要更多的字节, 你就完蛋了, 你的程序就不能工作了｡
必须返回并重新编译您｡
使用动态分配的字符串, 你可以重新调整, 你可以创建你所需要的内存,
这使得它在程序中更有效｡
所以你要在结构体内部创建的指针上使用malloc.
在本例中, 有一个名为name count的结构体｡
你有两个指针, 字符指针fname和last name｡
然后你有一个int, 字母｡
这里的两个字符串没有存储在结构中｡
我们只为包含地址的指针创建内存｡
我们要为fname和lname创建内存, 以存储指针所指向的内容｡
因此, 我们希望将其存储在由动态内存位置管理的块中, 这是使用malloc的｡
这两个字符串的地址是存储的内容, 而不是它们指向的内容｡
所以地址是字符串处理函数的典型对象, 这很好,
这就是为什么你要在这里使用指针,
因为这样你就不必那么做了, 你可以更容易地传递它们｡
这里有一个例子｡ 我们有一个名为get info的函数｡
它需要一个指针｡
我们可以很容易地传递指针｡
现在我们还要创建另一个或, 对于我们要传递给它的指针数组,
我们要为它分配内存｡
你会看到我们创建了一个名为temp的角色, 然后我们在这个temp中存储了一些数据｡
我们要求用户获取一些东西｡ 我们不熟悉sgets, 但它是一样的gets保存scanf一点｡
然后我们为指针内的fname分配内存, 就像为任何字符分配内存一样｡
我们调用malloc, 传入字节数｡
在本例中, 字符串长度为10加上1表示空终止符｡
然后记住, malloc变成了一个虚空星星, 所以我们把它投到了一个角色星上｡
但这一点很关键｡ 此malloc调用对于任何包含指针的结构都是必需的｡
现在我们传递了这个指针, 但是这个指针从来没有分配过内存｡
所以我们在这里分配内存｡ 这样我们就可以很容易地进行复制了｡
我们可以将temp复制到作为参数传入的结构pst的fname中｡
然后我们可以让他们输入他们的姓氏, 我们可以为姓氏分配更多的内存,
然后存储在姓氏结构变量中｡
这就是你需要做的当你的结构中有指向字符的指针时, 你必须做malloc｡
因为同样, 这些指针只存储地址｡
它们分配了足够的内存来存储地址, 而没有足够的内存来存储字符串｡
所以不管地址指向什么, 你都要分配内存,
就像正常的malloc一样, 唯一的区别是, 你用破折号大于号来访问结构体中的实际元素,
它是一个字符指针, 你可以把它赋值给它,
这样就完成了解引用.
所以你会想玩这些东西｡
这对于结构内部的字符指针来说非常常见｡
我们将有一个挑战, 你将需要这样做｡
但我们可以看看这段代码, 进入代码块,
开始为struct中的字符串或字符指针分配内存,
然后看看如何使用str copy将数据放入其中,
但首先必须在赋值之前分配内存｡
如果你像上一个例子那样做常量, 谁知道内存分配在哪里｡
所以, 在这节课上, 我们又讲了很多重要的概念｡
在这个新的语法中, 结构是一个指针, 你可以使用破折号,
然后大于, 而不是使用间接操作符,
非常好｡
然后实际上用元素作为指针, 以及如何为字符指针分配内存｡
-谢谢—谢谢