这个作业属于哪个课程 | 2024-2025-1-计算机基础与程序设计) |
---|---|
这个作业要求在哪里 | https://www.cnblogs.com/rocedu/p/9577842.html#WEEK09 |
这个作业的目标 | 操作系统责任、内存与进程管理、分时系统、CPU调度、文件、文件系统、文件保护、磁盘调度 |
作业正文 | 本博客链接 https://www.cnblogs.com/118qa/p/18565719 |
教材学习内容总结 | |
本周我们学习了指针的相关知识 | |
以下是对相关知识的总结 | |
一、指针的概念 | |
指针是一个变量,其值为另一个变量的地址。通过指针,可以间接访问和操作它所指向的变量。 | |
二、指针的声明 | |
声明指针的一般形式为:类型 *指针变量名; | |
例如:int *ptr; 这里声明了一个名为ptr的指针变量,它可以指向一个int类型的变量。 | |
三、指针的初始化 | |
可以在声明指针时进行初始化,将其指向一个已经存在的变量的地址。 | |
例如: | |
四、通过指针访问变量 | |
使用*运算符(解引用运算符)来访问指针所指向的变量的值。 | |
例如: | |
五、指针的运算 | |
算术运算: | |
当指针指向数组元素时,对指针进行加、减整数的运算,可以使指针指向数组中的其他元素。例如,若ptr指向数组arr的第一个元素arr[0],那么ptr + 1将指向arr[1](这里的偏移量根据所指数据类型的字节大小而定,对于int类型通常偏移 4 个字节,假设int占 4 字节)。 | |
两个指针相减可以得到它们之间相隔的元素个数(同样基于数据类型字节大小计算)。 | |
关系运算: | |
可以比较两个指针是否相等(指向同一地址)或判断一个指针是否大于、小于另一个指针(在指向数组等连续内存区域时有意义,可用于确定先后顺序等)。 | |
六、指针与数组 | |
数组名在很多情况下可以看作是一个指针常量,它指向数组的第一个元素的地址。 | |
可以用指针来遍历数组,例如: | |
七、指针与函数 | |
函数指针:可以声明一个指针来指向函数,其一般形式为:返回类型 (*函数指针变量名)(参数列表); | |
例如:int (*func_ptr)(int, int); 这里func_ptr可以指向一个有两个int参数且返回int类型的函数。 | |
指针作为函数参数:函数可以接收指针作为参数,这样可以在函数内部通过指针修改函数外部变量的值,实现 “传址调用”,常用于需要在函数中修改多个变量或者避免大量数据复制的情况。 | |
八、多级指针 | |
多级指针就是指向指针的指针。例如,int **pptr; 这里pptr是一个二级指针,它可以指向一个int *类型的指针变量。常用于动态内存分配等场景中需要传递指针的地址的情况。 | |
指针在 C、C++ 等编程语言中是非常重要且灵活的概念,熟练掌握指针对于深入理解内存管理、数据结构和函数调用等方面有着关键作用。 | |
教材学习中的问题和解决过程(先问 AI) | |
问题:指针运用与数组运用的区别? | |
AI:一、内存表示与本质 | |
数组: | |
数组是一块连续的内存空间,用于存储多个相同类型的数据元素。在内存中,数组元素是依次紧密排列存放的。例如,定义一个int数组int arr[5],系统会为这 5 个int类型的元素分配一段连续的内存空间,每个元素占据一定字节数(通常int占 4 字节)。 | |
数组名在大多数情况下可以看作是一个常量指针,它指向数组的第一个元素的地址,并且这个指向是固定的,不能对数组名进行赋值操作来改变它所指向的地址。 | |
指针: | |
指针是一个变量,其值是另一个变量(或内存单元)的地址。它本身在内存中有自己的存储位置,用来存放所指向对象的地址信息。例如,int *ptr;声明了一个指针变量ptr,它可以通过赋值操作指向不同的int类型的变量或者数组元素等。 | |
二、访问元素的方式 | |
数组: | |
可以通过下标来访问数组中的元素。例如,对于数组int arr[5],要访问第三个元素可以使用arr[2](数组下标从 0 开始计数)。这种方式直观且简单,直接根据下标在数组的连续内存空间中定位到相应元素。 | |
也可以将数组名当作指针来使用,通过指针算术运算的方式访问元素。比如arr + 2就指向数组的第三个元素(同样等价于&arr[2]),然后通过解引用操作*(arr + 2)也能获取到第三个元素的值,但这种方式相对下标访问来说在理解上可能稍微复杂一些。 | |
指针: | |
指针访问其所指向的变量或元素时,需要先通过赋值操作让指针指向目标对象,然后使用解引用运算符*来获取所指向对象的值。例如,int num = 10; int ptr = #,要获取num的值就可以通过ptr。 | |
如果指针指向数组元素,同样可以通过指针的算术运算(如加、减整数)来移动指针指向不同的数组元素,进而访问其他元素。比如ptr指向数组arr的第一个元素arr[0],那么ptr + 1将指向arr[1],通过*(ptr + 1)可获取arr[1]的值。 | |
三、可修改性 | |
数组: | |
数组一旦定义,其大小就固定了(在一些语言中不支持动态改变数组大小,如 C 语言中的静态数组)。不能直接在运行过程中随意增加或减少数组所占用的内存空间。 | |
虽然可以通过重新赋值数组元素来改变元素的值,但不能整体改变数组的存储地址(因为数组名是常量指针)。 | |
指针: | |
指针可以随时重新赋值,使其指向不同的对象(只要类型匹配)。例如,一个int指针可以先指向一个int变量,然后又可以指向另一个int变量或者数组中的某个元素等。 | |
通过指针的动态内存分配操作(如malloc、calloc等函数在 C 语言中),可以在运行时根据需要灵活地申请和释放内存空间,实现类似于动态改变数组大小的效果(但要注意内存管理,防止内存泄漏等问题)。 | |
四、作为函数参数传递时的特性 | |
数组: | |
当数组作为函数参数传递时,实际上传递的是数组的首地址(也就是数组名所代表的常量指针的值),在函数内部可以通过这个首地址和指针算术运算来访问数组的各个元素。 | |
由于传递的是首地址,函数内部对数组元素的操作会直接影响到原始数组中的元素(因为它们指向的是同一块内存区域)。 | |
指针: | |
指针作为函数参数传递时,传递的就是指针本身的值(即所指向对象的地址)。 | |
同样,函数内部可以通过接收到的指针来操作其所指向的对象,并且这种操作也会影响到指针所指向的原始对象(如果在函数内部对指针进行了重新赋值等操作,可能会改变其指向关系,这与数组作为参数传递时的情况有所不同,需要特别注意)。 | |
指针和数组在运用上各有特点,理解它们之间的区别对于正确、高效地进行程序设计和内存管理非常重要。 | |
基于AI的学习 | |
请你以指针的知识向我提问 | |
以下是一些关于指针知识的提问,来考考你对指针的掌握程度哦: | |
基础概念类 | |
在 C 语言中,声明一个能指向整型变量的指针,正确的语法应该是怎样的呢? | |
指针变量本身在内存中是占据一定空间的,那对于一个 32 位系统下指向整型(假设整型占 4 字节)的指针,它一般会占据多少字节的内存空间呢? | |
初始化与赋值类 | |
已知有一个整型变量int num = 20;,如何正确地初始化一个指针使其指向这个变量num呢? | |
若已经有一个初始化好指向某个整型变量的指针int *ptr;,之后能不能直接将它赋值去指向另一个不同的整型变量呢?如果可以,怎么做呢? | |
指针运算类 | |
设有一个整型数组int arr[] = {1, 2, 3, 4, 5};,同时有一个指针int p = arr;(即p指向数组的第一个元素),那么p + 2指向的是数组中的哪个元素呢?通过解引用(p + 2)又会得到什么值呢? | |
对于两个指针,比如int *p1和int *p2,它们都指向同一个整型数组中的不同元素,在什么情况下,p1 - p2这样的运算才有实际意义呢?运算结果又表示什么呢? | |
指针与函数类 | |
要声明一个函数指针,这个函数接受两个整型参数并返回一个整型值,该怎么正确声明呢? | |
当把一个指针作为函数参数传递给另一个函数时,在函数内部对这个指针进行了重新赋值操作,会对函数外部原来指向的对象产生什么影响呢? | |
多级指针类 | |
如何声明一个二级指针(指向指针的指针),比如是指向整型指针的二级指针,它的声明语法是怎样的呢? | |
已知有一个二级指针int **pptr;,怎样通过它来间接访问到最终所指向的整型变量的值呢? | |
不知道 | |
没关系呀,指针的知识确实有一定难度,下面我来给你详细讲讲这些问题的答案哦。 | |
基础概念类 | |
在 C 语言中,声明一个能指向整型变量的指针,正确的语法是:int *指针变量名;。例如:int *ptr;,这里ptr就是一个可以指向整型变量的指针变量啦。 | |
在 32 位系统下,无论指针指向的数据类型是什么(这里是指向整型,假设整型占 4 字节),指针变量本身在内存中一般都会占据 4 字节的内存空间哦。因为 32 位系统的地址总线是 32 位的,能表示的地址范围决定了指针需要用 4 字节来存储地址信息。 | |
初始化与赋值类 | |
已知有一个整型变量int num = 20;,要正确地初始化一个指针使其指向这个变量num,可以这样做:int *ptr = #。这里&num就是获取变量num的地址,然后把这个地址赋值给指针ptr,这样ptr就指向num啦。 | |
若已经有一个初始化好指向某个整型变量的指针int *ptr;,之后是可以直接将它赋值去指向另一个不同的整型变量的哦。假设又有一个整型变量int anotherNum = 30;,那可以这样赋值:ptr = &anotherNum;,这样ptr就从原来指向的变量变成指向anotherNum这个新的整型变量啦。 | |
指针运算类 | |
设有一个整型数组int arr[] = {1, 2, 3, 4, 5};,同时有一个指针int p = arr;(即p指向数组的第一个元素),那么p + 2指向的是数组中的第三个元素哦(因为数组下标从 0 开始,p指向arr[0],p + 1指向arr[1],p + 2就指向arr[2])。通过解引用(p + 2)会得到数组中第三个元素的值,也就是 3 啦。 | |
对于两个指针,比如int *p1和int *p2,它们都指向同一个整型数组中的不同元素,当我们想要知道这两个指针所指向的元素之间相隔几个元素时,p1 - p2这样的运算才有实际意义哦。运算结果表示的就是这两个指针所指向的元素之间相隔的元素个数(这里的计算是基于所指向数据类型的字节大小的,比如对于整型数组,每个元素占 4 字节,就会根据这个来准确计算相隔元素个数)。 | |
指针与函数类 | |
要声明一个函数指针,这个函数接受两个整型参数并返回一个整型值,正确的声明应该是:int (函数指针变量名)(int, int);。例如:int (funcPtr)(int, int);,这里funcPtr就是我们要声明的函数指针变量啦,它可以指向任何满足接受两个整型参数且返回整型值的函数哦。 | |
当把一个指针作为函数参数传递给另一个函数时,在函数内部对这个指针进行了重新赋值操作,会改变这个指针在函数外部原来指向的对象的指向关系哦。也就是说,函数外部原来通过这个指针能访问到的对象,在函数内部重新赋值后,就不再是原来那个对象了,而是变成了新赋值所指向的对象啦。所以在函数内部对作为参数传递进来的指针进行重新赋值操作要特别小心哦,不然可能会导致一些意想不到的结果呢。 | |
多级指针类 | |
要声明一个二级指针(指向指针的指针),比如是指向整型指针的二级指针,它的声明语法是:int **二级指针变量名;。例如:int **pptr;,这里pptr就是一个指向整型指针的二级指针变量啦。 | |
已知有一个二级指针int pptr;,要通过它来间接访问到最终所指向的整型变量的值,可以这样做:首先假设已经有一个整型指针int *ptr;并且pptr指向ptr(即pptr = &ptr;),然后假设ptr指向一个整型变量int num;(即ptr = #),那么通过pptr就可以间接访问到整型变量num的值啦。 | |
希望这些讲解能让你对指针知识有更清晰的理解呀,要是还有疑问,可以随时问我哦。 | |
其他 | |
本周写代码明显比之前熟练了,继续加油。 |