6. 几个经典的笔试题
❤️6.1 题目1:
问题1:
str传给GetMemory函数的时候是值传递,所以GetMemory函数的形参p是str的一份临时拷贝,在GetMemory函数内部动态申请空间的地址,存放在p中,不会影响外边str,所以当GetMemory函数返回之后,str依然是NULL。所以strcpy拷贝会失败。
问题2:
没有free释放,当GetMemory函数返回之后,形参p销毁,使得动态开辟的100个字节存在内存泄漏。
⭐️修改方法1:
我们就改成传址调用,利用二级指针接收!这样对形参的改变就会影响实参,此时把动态申请的空间交给指针p,其实就是给str!最后用完还要进行释放!
⭐️修改方法2:
不用传址调用怎么办呢?这就需要利用return指针返回来,这时我们还是用一级指针接收!因为是动态开辟的空间实际上是在堆区上开辟的,需要手动才销毁;我们把这个地址利用return带回来,然后在利用一个指针就接收就可以了!
比如:这种方法就可以应用在带头循环双链表中给头结点开辟空间,就可以利用return返回值的方式,避免使用二级指针!
❤️6.2 题目2:
问题:
同样是利用return返回值的方式,这里为什么就不行了呢?GetMemory函数内部创建的数组是在栈区上创建的,出了函数,p数组的空间就还给了操作系统,返回的地址是没有实际意义的,如果通过返回的地址,去访问内存就是非法访问内存!
❤️6.4 题目4:
问题:
看着好像是没什么问题,是传址调用,二级指针接收;主要就是,没有释放空间!free(str),str = NULL!
❤️6.4 题目4:
问题:
str已经释放了,下面就不能在访问,在访问就属于非法访问内存;为了避免这种错误发生:free过后一定要手动置空 str=NULL
❤️6.5 题目5:
问题:
(1)x是局部变量,在栈区上创建,出了这个范围,就把内存释放了,return(&x)没有实际意义!
(2)指针ptr才开始没有初始化,是野指针,里面放的随机值!
❤️6.6 经典例题补充
解析:
(1)对于#define定义符号,相当于替换,所以是int*a,b===>*说明a是指针,类型是整型;对于b只能说明是整型!所以如果我们要是一下子定义两个指针int*a,*b要写成这种形式。
(2)typedef是类型重定义,代表着一种类型;把int*起个别名叫int_ptr;所以c,d都是指针类型
7. C/C++程序的内存开辟
C/C++程序内存分配的几个区域:
1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。
2. 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。
3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。
补充:static关键字修饰局部变量的例子解释
实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序结束才销毁所以生命周期变长1
8. 柔型数组
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
8.1 柔性数组的特点
(1)结构中的柔性数组成员前面必须至少一个其他成员。
(2)sizeof 返回的这种结构大小不包括柔性数组的内存。
(3)包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
(4)柔型数组开辟的空间都是在堆上开辟的!
❤️例:
8.2 柔性数组的使用
❤️计算大小
❤️柔性数组的动态创建
(1)对于柔型数组的动态开辟空间,是用结构体指针(struct S* ps)进行接收;对于大小主要包括两部分:
一是n的大小创建,我们就用sizeof(struct S),这算的就是除柔性数组以外的大小;
二是柔型数组的动态开辟;其实就是开辟10个整型,我们就用10*sizeof(int);
(2)成功开辟后就使用,通过指针ps来查看内存发现已经被赋值;
(3)用完了,我们就用realloc进行扩容,这也就体现了柔性数组的特点,大小是可变的;我们用一个新的指针ptr进行接收,扩容成功后;把新指针ptr赋值给旧指针ps;
(4)最后在进行ps指针的释放,free(ps),ps = NULL ;
❤️利用指针实现柔型数组的功能
为了保证和柔性数组一样的性质,都是在堆上开辟的!我们所有的都需要用malloc开辟空间;柔型数组是一个malloc整体一块开辟的;用指针代替柔性数组,就要分开开辟:一个开辟除指针以外的大小的而空间;一个开辟指针所需大小的空间!
(1)利用指针代替柔型数组;实际上就是从一步到两步的过程;柔性数组只需要一次malloc;而指针形式就需要两次malloc;两次malloc就需要两次free;
(2)第一次malloc是动态创建除指针以外所需的空间;第二次malloc是动态创建指针所需大小的空间;
(3)成功开辟后就使用,通过指针ps->arr来查看内存发现已经被赋值;
(4)用完了,我们就用realloc进行扩容,我们就只需要对指针部分进行扩容;我们用一个新的指针ptr进行接收,扩容成功后;把新指针ptr赋值给旧指针ps->arr;
(5)最后在进行ps->arr指针和ps指针的释放,free(ps->arr),ps->arr = NULL ;free(ps),ps = NULL
9. 习题补充
❤️9.1 习题1
看着图形很简单,就打印两个对角线的位置;但是也要从中找到不变的量:一个对角线是i == j这个很容易看出来,另一条对角线呢?其实就是 i+j = n-1!
❤️9.2 习题2
首先我们要理清楚规律:1、3、5、7、8、10、12 是31天;4、6、9、11是30天;如果是平年2月份是28天,如果是闰年二月份是29天!31,28,31,30,31,30,31,31,30,31,30,31!
我们发现对于月份好像也没什么规律,都是有奇数也有偶数;数据也不多,不妨就写成数组的形式!
❤️9.3 习题3
我们在插入的时候,就面临一个问题:从前往后插还是从后往前插?如果从前往后插我们移动数据时就会造成数据的覆盖;所以我们就从后往前插入!