C博客作业05--指针
0.展示PTA总分
1.本章学习总结
1.1 学习内容总结
思维导图
指针与指针变量的概念
- 指针:内存中的一个存储单元的地址,即内存单元的编号
- 指针变量:声明一个变量并使用地址作为该变量的值,即一个能存放地址值的变量,通过它存放的地址值能间接访问它所指向的内容
指针变量的定义、使用方法、初始化
- 定义:类型名 *指针变量名。例如 : char *p;int *p ; 指针变量的类型应与其所指向内容类型一致
- 使用方法:使指针变量指向某个变量,(即将某变量的地址值赋给指针变量)。例如:int x; int *p=&a;使用指针变量时必须先赋值后引用,没有被赋值的指针是野指针,它所指向的内容无法确定
- 初始化:int a;int *p; p=&a; 指针变量不能被赋值,不能直接让指针指向整型数据,指针代表的是一个变量的地址。(可以将0或者NULL赋给指针,但是有的系统不支持赋0)
指针运算的优先级与结合性
- &a等同于a,均代表内容; &p等同于&a,均代表地址。(单目运算符优先级是相同的,但从右向左结合。)
- p++等同于(p++),代表的是内容。
- (p)++与(p++)的区别:前者是指针p所指向的内容自增相当于a++,而后者是运算完p所指向的内容后将指针向下移了一个位置
指针与动态内存分配
我们以往的定义如 :int a[10]; int b等等都是系统的静态内存分配,这些内存在程序运行前就分配好了,不可改变。但是如果我们不知道所输入的内存是多大时,我们定义内存的大小就不能够符合题目的输入,这时我们就应该使用动态申请内存。
malloc动态申请内存
int n;//记录输入总个数
int *p;
scanf("%d",&n);
p=(int *)malloc(n * (sizeof(int));
calloc动态申请内存
int n;//记录输入总个数
int *p;
scanf("%d",&n);
p=(int *)calloc(n , (sizeof(int));
realloc动态申请内存
int n;//记录输入总个数
int **p=NULL;
scanf("%d",&n);
p=(int **)calloc(p , n * (sizeof(int *));
动态内存释放
free();
动态申请内存后都要释放内存,避免数据泄漏和碎片化问题。一个动态申请对应一个释放函数。
malloc、calloc、realloc区别
- 相同点:都是从堆上申请空间;都需要类型转化(这三个函数返回值类型都是void);都需要用户free释放;
- 不同点:三个函数传入的参数不同;calloc会对申请空间初始化,并且初始化为0,而其他两个不会;realloc是对已经存在的空间进行调整,当第一个参数传入NULL的时候和malloc一样;
指针做循环变量做法
int a[20];
int n;
int *p;
p=a; //一维数组的数组名就是代表数组的首地址,一般不轻易改变原来的地址,引入一个新的指针变量去遍历
fgets(a,20,stdin)
for(p=a;*p&&*p!='\n';p++)
printf("%d",*p);
字符指针如何表示字符串
字符数组,指针遍历
char str[]="Hello,World";
char *ptr;
for(ptr=str;*ptr&&*ptr!='\n';ptr++)
printf("%c",*ptr);
指针指向字符串
char *str="Hello,World"
char *st;
st=str;
for(;*st&&*st!='\n';st++)
printf("%c",*st);
数组形字符串存放在全局数据区或栈区,可读可写。指针字符串存放在常量区,只读不能写
指针数组及其应用
定义:int *p1[]
int i;
char *pch[6]={"妹","妹","你","坐","船","头"};
for(i=0;i<6;i++)
printf("%s",pch[i]);
二级指针、行指针
二级指针
int i;
char *color[]={"red","blue","yellow","green","black"};
char **pc;
for(i=0;i<5;i++)
printf("%s",*(pc+i));
行指针
int i;
char color[6][7]={"red","blue","yellow","green","black"};
char (*p)[7];
for(i=0;i<5;i++)
printf("%s",*(p+i));
函数返回值为指针
查找子串
返回子串第一个字符所在位置用指针表示
char *match()
{
char ch,str[80],*s=str;
scanf("%s",str);
getchar();
ch=getchar();
while(*s!='\0')
{
if(*s==ch)
return s;
else
s++;
}
return (NULL);
}
1.2 本章学习体会
学习感受
指针类型的题集,我几乎都是用数组做的,因为数组先入为主,掌握基本的知识比之前做数组的题目要上手一些。我对指针的了解也只是皮毛,运用的不是得心应手。很多时候用数组可以处理的问题,用指针我反而不会了。何时使用指针会简化PTA的题目,而何时用指针反而使题目复杂化,对于这样的使用指针的一个程度我还没有把握到。指针的使用是有一个限度的,学习它就要找到那个限度才能算是真正的征服了指针,不然就是指针碾压我们。后续要再多练习,仍旧不能对指针有松懈,林老师说下周一指针测试的时候我的内心慌的不行。总感觉指针这一章,我什么都没学到,而且一直想知道明明学了数组,为什么还要再学指针(在我心里觉得指针和数组是等价的)!!!最明显的感受是这两周代码量明显降低了,而且学C的热情也有所降低,没有之前的关注了,之前一道题目我可以调试一个小时两个小时的,现在调半个小时我就烦了,会把问题拖到明天,之前是今天的问题今天一定要解决。因为心态发生变化了,积极性也降低了,后果就来了,上一次数组的小测,直接爆炸。这次的事情给了我提醒,要想学好一门语言,不拿出百分之二百的热情对待它根本学不好,中途也不能开小差,不能有任何的侥幸心理。坚持下去......一路走到底,未来仍可期。有一句话,要时时刻刻放在心上,铭记在心里。不忘初心,方得始终。想想当初学习IT的那份决心,万不可松懈。学习如逆水行舟,不进则退。可能是因为长时间的写博客作业,加上我们理科生对文字并不敏感,在完成博客作业上,我感觉到了逐渐的松懈,但是博客作业对我们来说是一种总结,我们不能把它当成作业来完成,而是要享受这个过程,这是一个自我复习、自我巩固的过程,也能帮助我们自我完善,改观疲倦心态,不忘初心!
代码量
2.PTA实验作业
2.1 题目名1-7-4 说反话-加强版
2.1.1 伪代码
定义一个字符指针char *str用来储存输入字符
定义一个整型变量int min用来储存第一个单词最后一个字符所在位置
动态申请字符指针的内存大小str = (char*)malloc(500005 * sizeof(char))防止栈溢出,所以在堆里申请
输入字符串
int len=strlen(str)-1;
int p=len;//每次输出最后一个单词后,长度要对应减少用p来储存
for int i=0 to len do i++
if(str[i]!=' ')
把此时的i储存在min中
break
end if
end for
for i=len-1 to 0 do i--
if (str[i] == ' ' && ((str[i + 1] >= 'a' && str[i + 1] <= 'z') || (str[i + 1] >= 'A' && str[i + 1] <= 'Z')))//找到最后一个单词的首字符
for int j=i+1 to p do j++
if (str[j] == ' ')
break;
end if
输出字符str[j]
end for
if((j-1)!=min)//防止最后一个单词多输出空格
输出空格
end if
p=i;
end if
end for
for i=0 to min+1 do i++
输出字符str[i]
end for
释放动态申请的空间free(str)
2.1.2 代码截图
2.1.3 总结本题的知识点
定义指针字符串,更能动态了解当初字符及其位置
如果头文件包括#include<string.h> 可以直接使用strlen函数
没有#include<string.h> 的头文件,就直接最字符串进行扫描让指针指到最后一个字符 while(*str&&*str!='\n') str++
找到字符串中第一个空格的位置,防止最后输出时字符串后面多了一个空格。
while(str[min]!=' ') min++;
找到子字符串的首字符,当前字符是空格下一个字符为字母就是子字符串的首字符
if (str[i] == ' ' && ((str[i + 1] >= 'a' && str[i + 1] <= 'z') || (str[i + 1] >= 'A' && str[i + 1] <= 'Z')))
2.1.4 PTA提交列表及说明
Q1:两个测试点没过,最大字符长度还有最后一个单词有空格
A1:重新写所有的代码,提交。
Q2:多种错误所有测试点都没有过,总感觉自己写的没毛病,可是它就是不按照我预期的输出
A2:有一个循环进入进入了死循环,而且有好几个循环即使满足了条件也不会进入,然后对这些问题进行修改,再提交
Q3:代码没有救了,各种测试点,各种错误,卡着,不给你过。
A3:没有办法了,只能去百度搜这道题目了。
Q4:运行我写的代码还是不能正确的输出,百度上的代码还使用了一个我之前没有见过的函数strtok,尽管是这样还是错了很多
A4:这个时候,代码的可读性已经很低了,参杂了自己的代码,还加入了百度上面的代码。我就决定在纸上重新整理一下自己的思路。
Q5:明明样例输出和我运后的结果是一样的,可是PTA这个测试点sample没给我过
A5:因为空格不好看出错误,我就把空格用#来代替,果然就发现了,输出后的字符在末尾都多加了一个空格,用一个变量储存第一个空格的位置,这样在输出空格时加一条判断语句,就可以末尾不输出空格
Q6:最后一个测试点,最长长度的字符串输出没过
A6:灵机一闪,把字符串长度比题目的要求加5,果然就过了
2.2 题目名2-6-9 合并两个有序数组
2.2.1 伪代码
定义一个整型指针*temp
动态申请空间temp = (int*)malloc((m + n) * sizeof(int))
for int k=0 to do k++
if(a[int i=0]<b[int j=0]
把a[i]储存在temp[k]中
i++
else
把b[j]储存在temp[k]中
j++;
ende if
end for
while(i<m) do
依次把a数组中剩余的元素赋值给temp
end
while(j<n) do
依次把b数组中剩余的元素赋值给temp
end
for i=0 to m+n do i++
把temp中的元素依次赋值给a数组
释放内存free(temp)
2.2.2 代码截图
2.2.3 总结本题的知识点
使用指针扫描两个有序数组并有序储存,运行时间少于先合并两个数组再将合并数组进行排序
两个数组长短不一样时,for循环结束时不能扫描完全,要继续用循环将没有扫描到的数组元素放入到temp中
2.2.4 PTA提交列表及说明
Q1:程序不能运行
A1:错误太多了,改一个又错一个,只能重新写程序了
Q2:写了一个新的代码,先合并两个数组再将合并数组进行排序
A2:部分正确,当两个数组的长度都达到极限时,运行超时。
Q3:上面那种情况我不知道怎么处理,就去向助教请教了....
A3:助教说,用一个新的数组存放两个数组元素较小的那一个数,又重新写过了代码
Q4:答案错误,数组储存不完整,没有把所有的元素都放进去
A4:用两个while循环,将没有遍历的元素放进新数组中去
2.3 题目名3- 删除字符串中的子串
2.3.1 伪代码
定义一个数组str1[83]用来储存主串
定义一个数组str2[83]用来储存子串
定义一个变量k用来储存当前主串所在位置
输入主串
输入子串
int len1=strlen(str1)-1
int len2=strlen(str2)-1
for int i=0 to len1 do i++
k=i
int j=0
while(str1[k] == str2[j]&&str1[k + 1]&&str2[j + 1]) do
k++;j++
end
if(str2[j] == '\0' ||str2[j] == '\n')
for int m=0 to len2 do m++
for int t=i to len1 do t++
将数组str1[]往前移,达到删除子串的目的
end for
给数组最后一个字符赋0
end for
len1=len1-len2
i=-1
end if
end for
输出数组str1[]
2.3.2 代码截图
2.3.3 总结本题的知识点
运用指针,判断主串里面是否含有子串,储存子串首字符在主串中的位置然后将主串向前移动len2次
主串删除子串后,长度减少len2,所有每一次删除后,都要对len1进行减法运算
len1=len1-len2
每删除一次子串后,让循环位置回到0,从头开始进行扫描,这样就能解决嵌套子串的问题
i=-1
2.3.4 PTA提交列表及说明
Q1:数据是原样输出,没有可删除的测试点可以过,与输出样例不符合
A1:修改代码,调试....
Q2:程序进不去是否为子串那个if语句的判断
A2:发现if语句变量写错了....修改代码
Q3:全删空的测试点可以过,但是样例仍然不能过,只能删除一次子串
A3:去百度了,阅读别人的代码,与我的结合起来
Q4:东拼西凑的代码显然过不了PTA的法眼
A4:没办法了,又去麻烦助教去了,他说每次删除完子串后,让最外层循环回到字符串的首字符进行重新扫描删除,重复上述工作,就可以了
3.阅读代码
代码功能
给定一组不同长度的木棒,是否可以将它们端对端地连接起来形成正方形,对于每种情况,如果可以形成正方形,则输出包含“yes”的行;否则输出“no”。
代码优点
- 使用bool函数,返回真假。而我一般使用flag或者是1/0判断真假,这个函数可以学习一下。
- 使用递归函数dog,刚好我们前两天也学了递归函数,学习该代码的优秀地方,dog函数是一个void函数类型,但是有一些判断语句后,加了return,直接结束了该函数的运行,方便而且节省时间
- 给a[0]=-100000,b[0]=1灵活赋值,然后代入dog函数里面,完成函数功能。