0.展示PTA总分
1.本章学习总结
1.1 学习内容总结
1.地址和指针
- 地址和指针是计算机中的两个重要概念,在程序运行过程中,变量或者程序代码被储存在亿以字节位单位组织的储存器中。在C语言中,如果定义了一个变量,在编译时就会根据该变量的类型给他分配相应大小的内存单元。
- 计算机为了对内存单元中的数据进行操作,一般是按“地址”存取的,也就是说对内存单元进行标识编号。如果把存储器看成一个建筑物,建筑物内的房间就是存储器单元,房间号就是地址。
- 要注意区分内存单元的内容和内存单元的地址。
2.指针变量的定义
- 如果在程序中声明一个变量并使用地址作为该变量的值,那么这个变量就是指针变量。定义指针变量的一般形式为:
类型名 *指针变量名
例如:int *p
- 类型名指定指针变量所指向变量的类型,必须时有效的数据类型,如int,float,char等。指针变量名时指针变量的名称,必须是一个合法的标识符。
- 定义指针变量要使用指针声明符*。
3.指针的基本运算
- 常用的字符串处理函数:
strlen 计算字符串s的长度
strcpy 把字符串t复制到s中
strcat 把字符串t连接到s,使s成为s和t连接后的新结果串
strcmp 逐个比较字符串s和t中的对应字符,直到对应字符不等或比较到串尾
strstr 在字符串s中查找字符串t首次出现的地址
- 与申请动态内存分配有关的函数
malloc 动态存储分配函数,申请空间并返回首地址
calloc 计数动态存储分配函数,申请空间并返回首地址,而且将存储块初始化为0
free 释放由动态存储分配函数申请到的整块内存空间,
- 在使用了malloc函数申请动态内存之后,一定要用free函数释放掉申请得来的空间。
4.二级指针、行指针
- 二级指针即指向指针的指针,一般的形式为:
int **pp
- 行指针,顾名思义就是指向一行的指针。那么哪里会用到行指针呢,用的最多的,那就是二维指针了,大家都知道,我们通常把二维指针看成一个行列式,但是它在内存中的排序却是和一维指针一样的。
- 比如组a[2][3]={{1,2,3}{4,5,6}},a是整个数组的首地址,同时也指向第一行元素,即a是一个行指针,它每加1,所指地址移动二维数组的一行,a+1指向第二行元素。
- 对a取,即a指向第一行第一个数,(a+1)指向第二行第一个数,可见,对行指针取值就成了列指针,此时它还是个指针。它每加1,所指地址移动一个元素,a+1指向第二行第二个元素,也可以写成a[1]+1。
**a
``` (也可写成a[0][0])就是这个二维数组第一行的第一个元素,```
**(a+1)
```(也可写成a[1][0])就是第二行的第一个元素,```
*(*(a+1)+1)
```(也可写成a[1][1])是第二行的第二个元素。可见,对行指针取2次*就成了某个元素的值了,而不再是地址。
**5.指针做函数返回值及其注意**
- C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的指针请尽量不要指向这些数据,C语言没有任何机制来保证这些数据会一直有效,它们在后续使用过程中可能会引发运行时错误。
###1.2 本章学习体会
**学习感受**
这两周进一步学习了指针的运用,同时也学习了递归的运用以及预编译的知识。但是可能是上周的线性代数期末考试,我大大减少了写代码的时间和数量,甚至好几天都没上PTA。因为一场期末考试将我的日常安排搞得一团糟,同时也反应了我平时学习的不够专注,课后没有及时补差,导致考试将至才发现我有许多内容都没掌握清楚。这种情况不只是在线性代数中体现,在我的其他科目也有体现。就在上周,我甚至还弄不懂指针的用处到底是什么?我被自己这种状态吓到了,反省过后发现还需要继续努力。规律日常作息,及时补差,上课集中注意力,将需要完成的任务规划到每一天,让自己充实起来。我相信,只要静下心来,一步一步慢慢走,总能解决所有的问题。希望自己继续努力吧。
**代码量统计**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191204215226804-265799489.png)
##2.PTA实验作业
****
###2.1 PTA题目1
2019-c10-指针
6-9 合并两个有序数组(2)
要求实现一个函数merge,将元素个数为m的升序数组a和长度为n的升序数组b合并到数组a,合并后的数组仍然按升序排列。假设数组a的长度足够大。
**2.1.1 伪代码**
void merge(int* a, int m, int* b, int n)
定义循环变量i, j, k, 并赋值i = m - 1; j = n - 1; k = m + n - 1;
定义指针c int *c
申请空间c = (int*)malloc((m + n) * sizeof(int));
while i >= 0 && j >= 0
if a[i] > b[j] then
c[k--] = a[i--];
else
c[k--] = b[j--];
while i >= 0
c[k--] = a[i--];
while j >= 0
c[k--] = b[j--];
for i = 0 to m+n-1 do
a[i] = c[i];
free(c);
**2.1.2 代码截图**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191201104410167-1157523001.png)
**2.1.3 总结本题知识点**
1.当进行两个有序数组的连接并重新排序时,个人认为从大的开始排序会更理解一点
即: while (i >= 0 && j >= 0)
{
if (a[i] > b[j])
{
c[k--] = a[i--];
}
else
{
c[k--] = b[j--];
}
}
2.当申请了动态空间时,结束时要记住释放。
3.当两个数组大小不一样时,当较小数组遍历完后,要记得处理另一个数组的剩余数据
即: while (i >= 0)
{
c[k--] = a[i--];
}
while (j >= 0)
{
c[k--] = b[j--];
}
4.后来测试发现从大的开始输出时,可以不需要重新再定义一个*c,可以直接在a数组上进行重构,这样可以大大减少代码量。
**2.1.4 PTA提交列表及说明**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191201105425037-301431396.png)
Q1:编译错误
A1:编写代码时忘记加分号
Q2:部分正确
A2:一开始没有看清楚题目,以为是两个函数,所以一开始做的方法是直接将b数组连接到a数组后方,在第二个函数输出是再开始排序,后来发现只用一个函数,于是改用循环比较大小开始重构a数组,但是当n很大时就会超时。
Q3:全部正确
A3:林丽老师讲了之后,我尝试用逆着输出,思路与林丽老师的差不多,定义了一个*c,申请动态空间是为了防止越界,从大的开始往前赋值,最后将c数组的值重新赋给a数组,完成题目。
****
###2.2 PTA题目2
2019-c10-指针
6-5 字符串反正序连接
先将在字符串s中的字符按逆序存放到t串中,然后把s中的字符按正序连接到t串的后面.
**2.2.1 伪代码**
void fun(char* s, char* t)
定义count = 0;
定义指针char * p;
p = s;
while *p do//计算传入字符串的长度
count++;
p++;
for p--; count; count--, p--, t++ do
*t = *p;//此时的p指向的地址是字符串的最后一位,所有从后往前赋值给t,即倒序赋值;
for p = s; *p; p++, t++ do
*t = *p;//进行上一步循环后,p指向的地址变为第一位,正序赋值
*t = 0;//再赋值完后加结束符号
**2.2.2 代码截图**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191203192826724-393689910.png)
**2.2.3 总结本题知识点**
1.再定义指针,进行循环计算字符串长度时,地址要记得一起自增
即:while (p)
{
count++;
p++;
}
2.在对t进行重新赋值后要记得加结束符
即:t = 0;
3.在进行循环时要对循环条件判断,变量的变化做好判断
**2.2.4 PTA提交列表及说明**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191203202413904-370005962.png)
Q1:答案错误
A1:一开始没有定义*p,而是定义了一个字符串来储存传入的字符串再进行倒叙的赋值,虽然在VS中的测试值与样例答案一样但是PTA的测试却显示答案错误,同时有可能会造成字符数组的对应数值的错误
Q2:全部正确
A2:后来重新看来超星视频和翁恺老师的关于指针的视频课后,对指针有了重新的认识,就有了现在这个代码的思路,利用一个新指针的地址来进行赋值,这样不会造成数值的错误,同时也精简了代码。
****
###2.3 PTA题目3
2019-c10-指针
7-2 藏尾诗
本题要求编写一个解密藏尾诗的程序。
**2.3.1 伪代码**
include<stdio.h>
include<string.h>
int main()
定义字符数组w来储存藏尾诗的输出内容 char w[16];
定义s来储存诗词 char s[4][20];//储存诗词
定义len来储存每行诗词的长度;
定义循环变量i;
for i = 0 to 3 do
scanf("%s", &s[i]);
for (i = 0 to 3 do
len = strlen(s[i]);//计算每一行的长度
w[2 * i] = s[i][len - 2];//最少1个汉字,最多9个汉字
w[2 * i + 1] = s[i][len - 1];
w[2 * i] = ' ';
puts(w);
return 0;
**2.3.2 代码截图**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191203221751866-924709390.png)
**2.3.3 总结本题知识点**
1.一个汉字是占两个字节,因此在寻找对应位置的时候要注意
即: w[2 * i] = s[i][len - 2];//最少1个汉字,最多9个汉字
w[2 * i + 1] = s[i][len - 1];
**2.3.4 PTA提交列表及说明**
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191203221837286-556214429.png)
Q1:全部正确
A1:两次运用了不同的写法,第一次是一次遍历每一行的字符串,找到最后一个汉字后进行储存。这个新的代码思路大同小异,但是是对新字符串进行赋值,同时代码会精简很多。
****
********
##3.阅读代码:
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191204214613869-139407875.png)
![](https://img2018.cnblogs.com/blog/1772965/201912/1772965-20191204215322441-1020244397.png)
- **代码功能**
首先在第一行输入两个数字,这两个数字将用作矩阵中的行数(R)和列数(C)。然后部门输入信息的字母,沿着矩阵以螺旋模式编码。输入0 0,则结束程序,不做读取,然后对密文进行解密,最后输出解密完成后的字符串
- **代码优点**
1. 该代码对于二维数组的处理十分厉害,定义了多个变量来对二维数组进行处理。
2. 结构严谨,for循环,while循环,if语句的运用十分恰当,衔接的地方也处理得当,没有造成代码的多余和复杂。
3. 多次运用getchar()来吸收换行符。