C博客作业05--2019-指针
0.展示PTA总分
1.本章学习总结
1.1 学习内容总结
1.指针做循环变量做法:
- 首先,最基本也是指针最重要的一点——使用之前必须给指针变量赋值或者分配存储空间,否则,指针的值便是不确定的,不能明确它所指的内存单元,因此引用这种未赋值的指针时,可能会出现难以预料的结果或错误。
- 然后就是要注意指针下标的范围和指针的结束符。指针和数组一样,都需要一个结束符来作为循环条件,否则容易造成数组越界。如果是用下标来做循环的判断条件的话还需要提前计算指针中的内存单元格数。
2.字符指针如何表示字符串:
- 要表示字符串的话,首先这个指针的定义必须是char型的指针。然后需要另外定义一个一维的char型数组来存放字符串。最后在将char型字符串的首地址作为初始值赋给char型指针。
- 也可以先将未赋值的char型数组的首地址作为初值赋给char型指针,然后直接输入字符串作为指针的内容。
- 还可以先给指针分配内存单元,然后再输入字符串给内存单元。
3.动态内存分配:
- 我们上面说了,使用指针值之前必须先给指针赋初值或者分配内存单元。而动态内存分配就是给指针分配内存空间的一个过程。
- 在进行动态内存分配之前首先需要了解指针需要多少内存空间,这一点需要根据题目或者用户需求来判断。
- C语言的动态内存分配函数有两个:malloc函数和calloc函数。二者的区别是malloc函数对所分配的储存块不做任何事情,而calloc函数会对整个区域进行初始化为0。
- 最后,俗话说的好:“有借有还再借不难”。在我们使用完动态内存分配的指针后,需要运用free函数来释放我们之前所申请的动态内存,否则容易造成内存碎片,严重的还可使系统崩溃。
4.指针数组及其应用:
- 与二维数组名类似,指针数组名也是二级指针。指针数组里面的内容还是指针,也就是地址,指针数组里的指针所指的才是内容。
- 例如给定一个指针数组指向一个二位数组,那么指针数组中的每一个下标内容对应的便是二维数组的该行的内容。
- 应用:指针数组可以用来输入和输出一整串字符串。例如一首诗,那么每个指针下标对应的内容便是该行诗的内容。通过指针数组不仅可以对多个字符串整体操作,还可以对字符串中的字符进行操作。
5.二级指针、行指针:
- 二级指针就是指向一级指针的指针,定义方式为:
char **p
。而行指针就相当于二维数组的数组名。 - 假如定义一个变量a,一个一级指针p指向变量a,一个二级指针pp指向一级指针p。那么pp便是p的地址,与&p等价;而
*pp
就是p指针所指向的地址,即*pp
与p,&a等价;**pp
就是p所指向的地址的内容,即**pp
与*p,a
等价。 - 对于行指针,假如定义一个二维数组a[4][4],那么数组名a就是一个行指针,a的值就是二维数组的首地址,即a[0][0]的地址。而a[i]是列指针,它的值同样也是二维数组的首地址a[0][0]。二者的区别是:如果对行指针进行加减运算的话,那么就相当于换行操作,即改变指针的的值使其指向下一行的内容,例如
a+j
即代表第j行的所有元素;而对列指针值进行加减运算的话就相当一在a[i]行对该行的元素进行加减,例如a[i]+j
就是指第i行的第j个元素。
6.函数返回值为指针:
- 如果要让函数的返回值为指针的话,首先这个函数必须定义成指针型函数。
- 对于作为返回值的指针,这个指针不能是在函数内部定义的局部数据对象的地址。因为所有的局部数据对象在函数返回时就会消亡,其值便不再有效。
- 所以,返回指针的函数一般都返回全局数据对象或主调函数中数据对象的地址。
1.2 本章学习体会:
- 学习感受:指针作为c语言的灵魂,其理解的困难程度真的是不容易,要想学好指针必须多下点功夫,多花点时间和精力去研究。而且在使用指针的时候很容易出错,重点是出错了还
看不懂报错信息,这是最致命的。看来还是得多做点题目,多熟悉熟悉指针的用法。 - 不理解的地方:感觉运用指针时VS的所有报错信息都看不懂,不知道自己错在哪。
- 代码量:这两周的代码量大概在900行左右,
不达标。
2.PTA实验作业:
2.1 6-9 合并两个有序数组(2):
2.1.1 伪代码:
- 数据处理:
变量 | 作用 | 类型 |
---|---|---|
i | a数组的下标 | int |
j | b数组的下标 | int |
k | 指针c的下标 | int |
c | 存放合并后的新数组 | int* |
- 伪代码:
初始化i,j,k的值为0.
运用molloc函数来为c指针动态分配内存。
while(i小于m并且j小于j)
对比a[i]和b[j],将较小的数存入c中,同时较小的数组和c的下标同时自增1.
end while
while(i小于m)
将剩下的a数组中的值顺序存放在c中。
end while
while(j小于n)
将剩下的b数组中的内容顺序存放在c中。
end while
for i from 0 to m+n-1
将c中的内容重新赋值给a数组。
end for
2.1.2 代码截图:
2.1.3 总结本题的知识点:
1.掌握合并有序数组的方法:
while (i < m && j < n)
{
if (a[i] < b[j])
{
c[k++] = a[i++];//将a数组的内容赋给c
}
else
{
c[k++] = b[j++];//将b数组的内容赋给c
}
}
2.注意判断end while 之后a数组和b数组是否有剩余内容,如果有的话将剩余内容顺序存入c。
3.注意在函数末尾释放前面为指针c动态申请的内存。
2.1.4 PTA提交列表及说明:
- 提交说明:
1.编译错误:一开始做的时候没注意题目还定义了一个打印数组的函数。
2.部分正确:我一开始做的时候是先将a和b数组全部存放在c中,不论顺序的,然后再去重新对c中的内容排序,用到了好几个for循环,导致测试数据非常大的时候就会运行超时,过不了测试点。
3-4.部分正确:同上。
5.多种错误:在修改的过程中没注意数组的结束条件,导致栈溢出加上运行超时,结果就多种错误了。
6-7。部分错误:后来改用老师的方法时,没注意,在给指针c赋值的时候a数组或者b数组的下标自增了两次,导致部分测试点过不了。
8-10.全部正确:在多次修改之后达成了题目要求。
2.2 7-2 藏尾诗:
2.2.1 伪代码:
- 数据处理:
变量 | 作用 | 类型 |
---|---|---|
len | 储存当前行的字符长度 | int |
i | 数组和指针数组的下标 | int |
p | 存放一整首诗的指针数组 | char* |
poem | 存放输入的每一行诗 | char |
- 伪代码:
while i小于4 //题目明确是四句诗
用molloc函数为p[i]指针动态分配内存;
输入一句诗;
getchar()吸收回车符;
用strcpy函数来给p[i]指针赋值;
i++;
end while
for i form 0 to 3
len=当前诗句长度;
(p[i]+len-2)就是当前诗句的最后一个字,用printf输出即可;
end for
2.2.2 代码截图:
2.2.3 总结本题的知识点:
1.对于指针数组,一次只能给一个指针动态申请内存,不能一次性给一整个指针数组动态申请内存。
2.如果是用scanf函数来输入诗句的话要注意用getchar函数吸收回车符。
3.一个汉字占两个字节,所以每一句诗的最后一个字的地址是:诗句首地址+诗句长度-2.
4.与动态申请内存一样,释放内存也得一个一个指针来,所以在每一次for循环打印最后一个字后都要用free函数释放当前指针的内存。
2.2.4 PTA提交列表及说明:
- 提交说明:
1.这题我是在VS上经过多次调试后,能过了题目所给的测试点之后才拿到pta提交的,然而还是错误。
2.段错误:一开始我是打算再定义一个数组来存放每一句诗的最后一个字,然后再逆序输出的,然而费时费力还因没有给该数组结束符导致段错误。
3.答案正确:后经舍友指导,改了一下做法:直接输出当前诗句的最后一个字。完美解决了问题。
2.3 7-4 说反话-加强版:
2.3.1 伪代码:
- 数据处理:
变量 | 作用 | 类型 |
---|---|---|
str | 存放输入的字符串 | char |
endPtr | 作为逆序遍历的起始条件 | char* |
p | 控制遍历循环开关 | char* |
len | 判断一个单词的字母个数 | int |
flag | 判断遇到的第一个空格是不是第一个空格 | int |
- 伪代码:
主调函数main()
{
输入一串字符存入str中;
将str的首地址传到函数ReverseStr中;
return 0;
}
逆序输出函数ReverseStr(char* beginStr)
{
给flag赋初值1;
将beginStr作为初值赋给endPtr;
while *endPtr不等于0并且不等于换行符\n
endPtr++;
end while
将--endPtr作为初值赋给p;
初始化len的值为0;
while p不等于beginStr
if *p不等于空格
len++;
if*p的前一个字符等于空格
输出当前len个字母的单词;
flag值改为0;
else
输出当前len个字母的单词,不修改flag的值;
将len的值清零;
p的地址往前移动一个单位;
end while
if 字符串第一个字符不是空格
if 该字符之前没有遇到过空格
打印该len+1个字母的单词;
else
先打印一个空格再打印该len个字母的单词;
}
2.3.2 代码截图:
2.3.3 总结本题的知识点:
1.掌握了逆序遍历数组的方法。
2.掌握了判断一个单词是否结束的方法。
3.了解了指针作为数组的另一种输出方式。
2.3.4 PTA提交列表及说明:
- 提交说明:
1.多种错误:刚开始看到这个题目的时候无从下手,像一只无头苍蝇一样到处乱撞,导致多种错误。
2.编译错误:同上。
3.多种错误:同上。
4.部分正确:有了一点点头绪,但只能过最简单的一个测试点。
5.答案正确:去网上找了一下别人的做法,复制到pta验证,结果就正确了。。。
6-7.部分正确:按照老师教的做法修改了一下之后,还有一个测试点过不了。
8.编译错误:一个大括号忘记加了。
9.答案正确:在舍友的指导下结合老师的做法,答案正确了。
3.阅读代码:
- 代码功能:输入一个字符串和一个子串,找到并删除字符串中的所有子串。
- 优点:该作者脑回路非常新奇,不是用传统的运用数组移动来删除字串,而是将子串在字符串中的首地址内容改为
'\0'
,然后再将字符串与子串后的内容连接起来,因为strcpy连接函数
是从'\0'
开始连接的,所以就巧妙的达到了删除子串的目的。该作者很了解strcpy连接函数
的特点和用法,从而仅仅用了短短的二十行左右的代码就实现了删除子串的功能。 - 可以学习的地方:该作者所用到的
strstr
查找子串在字符串中的首地址这个函数值得我学习,运用这个函数,可以事半功倍的查找子串在字符串中的首地址;该作者对strcpy连接函数
的用法值得我学习,看了这个代码我才知道strcpy连接函数
原来是从'\0'
开始连接的,还是得多多了解相关函数。