0.展示PTA总分

1.本章学习总结

1.1 学习内容总结

指针做循环变量做法

重点是要记得定义新的指针,保留原指针地址!

以下是以a为字符串数组为例,因此循环结束条件就是为结束符时。

注意循环时,判断循环结束条件是利用新定义的指针,同时自增的也应该是新定义的指针。

int a[];
int* p = a; for (; *p; p++)
{
...
}
while (*p)
{
p++;
}

字符指针如何表示字符串

字符串和字符指针

如果定义一个字符指针接收字符串常量的值,该指针就指向字符串的首字符

例如:

char s[] = "array";
char* p = "point"; 字符串与字符指针都能处理字符串,但两者之间有重要区别: 字符数组s在内存中占用了一块连续的单元,有确定的地址,每个数组元素放字符串的一个字符,字符串存放在数组中。 字符指针s只占用一个可以存放地址的内存单元,存储字符串首字符的地址,而不是将字符串放到字符指针变量中去。

易错点:

  • 直接给数组名赋值

char a[MAX]; a = "hello"

是非法的!因为数组名是常量不能对它进行赋值。

  • 引用未赋值的指针
char* s;

scanf("%s", s);

定义字符指针后,如果没有对它赋值,指针的值是不确定的,不能明确它指向的内存单元。

应该改成:


char* s,str[20]; s = str; scanf("%s", s); 数组str有确定的存储单元,s指向数组str的首元素,并对数组赋值。

!:为了尽量避免引用未赋值的指针所造成的危害,在定义指针时,可先将它的初值置空,如:

char *s = NULL;

动态内存分配

在进行动态存贮分配的操作中,c语言提供了一组标准函数,定义在stdlib.h里面

(1) 动态存储分配函数malloc( )

函数原型:

void *malloc(unsigned size)

功能:在内存的动态存储区中分配一连续空间,其长度为size.

若申请成功,则返回指向所分配内存空间的起始地址的指针;若申请不成功,则返回NULL(值为0)

malloc()的返回值(void *)类型。

在具体使用中,将malloc()的返回值转换为特定指针类型,赋给一个指针

例如:

if((p=(int *)malloc(n*sizeof(int)))==NULL)

调用malloc()时,应利用sizeof计算存储块大小,不要直接写数值,因为不同平台数据类型占用空间大小可能不同

!:注意不要越界使用。

(2) 计数动态存储分配函数calloc( )

函数原型:

void *calloc (unsigned n,unsigned size)

功能:在内存的动态存储区中分配n个连续空间,每一存储空间的长度为size,并且分配后还把存储块里全部初始化为0。

!:malloc()对所分配的存储块不做任何事情,calloc()对整个区域进行初始化

(3)动态存储释放函数free()

函数原型:

void free ( void *ptr)

功能:释放由动态存储分配函数申请到的整块内存空间,ptr为指向要释放空间的首地址。如果ptr是空指针,则free什么也不做。该函数无返回值。

!:释放后不允许再通过该指针去访问 已经释放的块,否则也可能引起灾难性的错误

(4) 分配调整函数realloc( )

函数原型:

 void *realloc(void *ptr,unsigned size)

功能:更改以前的存储分配。ptr必须是以前通过动态存储分配得到的指针。参数size为现在需要的空间大小。

如果size小于原块的大小,则内容为原块前size范围内的数据;如果新块更大,则原有数据存在新块的前一部分。

如果分配成功,原存储块的内容就可能改变了,因此不允许再通过ptr去使用它。

指针数组及其应用

如果要使用多个字符串,通常使用二维字符数组或者指针数组

例如:


char a[5][20]; char* b[5]; char **pb;
pb = b;

定义时:

二维数组时必须指定列长度,该长度要大于最长字符串的有效长度。

由于各个字符串的长度一般并不相同,会造成内存单元的浪费。

而指针数组并不存放字符串仅仅用数组元素指向各个字符串,就没有类似问题。

指针数组与二维数组名类似,都是二级指针,因此数组下标与指针可互换使用:

据上面例子,此时pb指向b数组首元素b[0]

pb等价于b[0] 代表同一个存储单元,都指向b中第一个字符串

因此,
(pb+i)等价于b[i] 代表b中第i个字符串的地址

**(pb+i)等价于b[i] 代表的是b数组中第i个字符串的第一个字符

同样的有 (pb + i)+j)等价于
(b[i]+j)

二级指针、行指针


1.行指针: int(*p)[n] //注意括号!!! 含义:p为指向含有n个元素的一维数组的指针变量,是二级指针! p + i = a + i 二级指针 p + i表示第i行的首地址a[i]
* (p + i) = *(a + i) = a[i] 一级指针 两次 * 才表示内容 行指针可以和数组名互换用.
//同样要注意括号 p[i][j] = a[i][j] * (*(p + i) + j) = a[i][j] (*(p + i))[j] = a[i][j] 2.列指针: int* p;
p = a[0]; *(p+i) 表示的是离a[0][0]第i个位置的元素

函数返回值为指针

返回指针的函数一般都返回:

  • 全局数据对象
  • 主调函数中数据对象的地址
  • ** 堆区的指针**
  • ** 指向字符串常量的地址**
  • ** 指针数组**

指针作为函数的返回值,要注意的是:

不能在实现函数时返回在函数内部定义的局部数据对象的地址。(因为所以的局部数据对象在函数返回时就会消亡,其值不再有效)

1.2 本章学习体会

  • 本章学习指针时,一开始在二维指针,指针数组,二维数组部分很混淆,在预习时懵懵懂懂,上课时加深了印象才真正理解了的感觉。感觉一定是需要课前预习的,这样上课吸收的快

    加深印象后,也更有助于理解。

  • 然而一开始练习指针题目时,又感觉是一切归0。虽然是听懂了,但还没法马上应用,就指针数组和二维数组的区分不够清晰,下标及指针互通使用的方法也不熟。

    一开始就找的最简单最基本的题,然后一边复习书本上的经典例题,一边学习编写。

    并且在编写过程中,尽量分装函数,做正确了之后,二维数组和指针数组尽量都尝试使用,下标和指针也尽量都尝试使用。这样实践练习以后才慢慢熟悉起来。

  • 本章代码量约1050行

2.PTA实验作业

2.16 -7 输出月份英文名

2.1.1 伪代码


char* getmonth(int n)
{ char* month[12] = { ... }利用指针数组储存每个月份的英文名 if(n为1到12月份) 返回对应月份地址month[n-1]//需注意的是这里的下标应该是n-1,而不是n else 返回空指针 }

2.1.2 代码截图

2.1.3 总结本题的知识点



	知识点://该题知识点较简单,但也最为基础经典

      该题反映了如何使用指针数组来记录多个字符串
char* month[12] = { ... }; 在主函数中,记录多个字符串也可以利用二维数组定义,如:
char month[12][20];//12个月份,每个英文字符串最多20个字节 总结: 通常,要记录多个字符串时,利用二维数组和指针数组均可。 比较:利用指针数组的好处是不用考虑每个字符串的长度,而二维数组则一一对应更为直观好理解 需要注意的是!** 该题是函数接口,因此应当返回有效的指针地址,因此只能利用指针数组来做,不能直接用二维数组定义** ** 拓展**//老师上课拓展的笔记 返回指针的函数一般都返回** 全局数据对象** ,** 堆区的指针** ,** 指向字符串常量的地址** ,** 主调函数中数据对象的地址** 或** 指针数组** 。 因此若一定要使用二维数组,应当如下修改: static char month[12][20];//

2.1.4 PTA提交列表及说明

该题较基础简单,所以PTA上一次就过,但在实际操作中,由于是第一个练习的题目,仍有许多值得学习、值得回忆的地方。

  • 1.一开始想要利用指针数组编写。然而在实际编写过程中总是有红色的波浪线,(也就是语法错误)。于是我只好换种写法,利用二维数组编写,在编写过程中显然语法是没错的,但运行测试时却是一大堆奇怪的字符,这让我百思不得其解。

  • 2.最后上课时老师也进行了解释,由于该题做的是函数接口,在函数中定义的只是局部变量,当返回时也已经消亡了,所以才会出现一大堆奇怪的字符,因为地址已经不知道指到哪去了。书本上预习时也有读到相关内容,但是在真正应用中还是没法马上反应过来,而经过这题,对在分装函数中返回有效的指针地址有了更多的理解。同时课堂上也拓展了在返回指针的函数中哪些能返回,以及该题目利用二维数组的方法(总结在上部分的知识点中)

  • 3.最终我是利用指针数组写的,但在编写过程中,总是出现红色波浪线(说明语法错误)。因此上百度搜索。

    最终解决办法是:在VS编译器 属性-> c/c++ -> 语言 -> 修改符合模式

2.2 6-6 查找子串

2.2.1 伪代码


char* Search(char* s, char* t)
{ char* ps;用来保存s串中出现相同的第一个字符的地址
char* pt = t;用来保存t串的首地址 while (*s!=0) //遍历s字符串
{
if (s中的某个字符与t串第一个字符相同)
{
ps = s; 记录出现相同第一个字符的地址 while 遍历t串
{ if (比较字符若不同) break;
else 地址自增,继续比较 } if (若t串全部遍历) 则说明其后的字符也都相同,返回地址ps 若进行到这步则说明不同,由于比较过程中指针移动了,因此将s恢复到已经比较的位置,t恢复到首地址,以便下次比较。
即 s = ps;t=pt }
s++;
} if(若s串全部遍历) 则说明s中找不到t串,返回空指针 }

2.2.2 代码截图

2.2.3 总结本题的知识点


1.本题最主要的是思路: 遍历s串,一旦发现与t串第一个字符相同就进行下一步比较。 一旦相同,就得继续比较,保证其后的字符也都是相同的才正确。 2.比较时,利用指针同时自增的方法 if (*s != *t)
{ s++; t++; } 3.注意点:**是利用指针在进行循环时,记得保留地址** 在本题中,利用指针*ps和*pt更是巧妙: //要注意,在比较地循环中,指针一直在移动,而当不满足字符串相同条件时,就需要**恢复初始地址**,以便下次的循环比较。 char *pt=t//pt保存的是t串首地址 while (*s)
{
if (*s == *t)
{ ps = s;//ps记录第一个字符相同的地址
... }
}

2.2.4 PTA提交列表及说明

在PTA上的提交是一次就过,其实在VS上调试了很多遍才通过,而且该题运行一下,基本上就可以知道会不会通过了。

该题较易混乱的是比较时候,编写代码语言的逻辑性。

  • 在编写过程中,一开始也注意了,一旦比较不相同,记得要将地址恢复到初始位置,才能进行下次比较。

    但是调试了发现结果却不对,逐语句调试过程中才发现,只有t串是恢复到首地址位置比较的,而s串应当是恢复到已经与t串第一个字符比较完的字符位置因此必须记录s与t第一个字符相同时的位置,并且应当将指针恢复到该位置,否则就会进入死循环,一直从头比较而无法结束。

2.3 6-9 合并两个有序数组

2.3.1 伪代码

void merge(int* a, int m, int* b, int n)
{
数据处理: int* c;开辟一个新数组c来存储新序列,最后再赋值给a数组来达成题目要求
int* pc;主要用来保存c数组的首地址
int* pa = a;
int* pb = b; 分别利用两个指针,对a, b数组进行操作 为c数组动态申请内存
并且立刻保存下c的首地址(pc = c; ) for 遍历c数组
{ if 若a,b数组均未扫描结束
{ if a中元素小于b中元素
将a中该元素赋值给c,并且移动指向a的指针 else 反之,将b中该元素赋值给c,并且移动指向b的指针 } else if 若a扫描未结束,只将a剩余的赋给c else if 若b扫描未结束,只将b剩余的赋给c else break;都扫描结束直接跳出循环
} 将c恢复至首地址位置(c = pc; ) while 遍历c数组
将c一一赋给a }

2.3.2 代码截图





2.3.3 总结本题的知识点

1.该题的重点解法:

利用先插入再利用冒泡或是选择排序的方法,当序列较大时,并且在两个数组已然是有序的情况下,明显是费时费力,也容易超时。

因此采用将a,b中元素一一比较,通过开辟一个新数组c来存入比较后的新数列。

重点是,该比较并非是同时自增比较。因此应当注意,比较完存储进c的指针才自增移动,以及当其中某一个数组都扫描完成后,

另一数组的剩余元素则可直接赋给c数组。

2.其他解法:

void merge(int* a, int m, int* b, int n)
{ int i = m - 1;
int j = n - 1;
int k = m + n - 1; while (j >= 0)
{
a[k--] = i >= 0 && a[i] > b[j] ? a[i--] : b[j--];
} } 该解法大致相同,区别是该做法是**从后**开始比较赋值。 由于a已申请的内存是m+n,而目前a中仅有m个元素,而a数组的后半部分是空的。 从后开始比较,这种做法更为巧妙,由于后半部分本就是空,这样就**不用再开辟新数组存储了** 3.学会用动态申请内存 c = (int*)malloc((m + n) * sizeof(int)); 4.使用完的动态内存应当及时free()//是老师讲解过程,发现自己代码的不足

2.3.4 PTA提交列表及说明

  • 1.指针写法不娴熟:第一次提交内容是在机房实验课写的。当时写完了之后,由于时间比较紧迫,我就直接尝试提交,但是却没一处正确。

    由于该题目属于指针题集,于是在编写过程中我有意的使用了指针来指向(为了再多熟悉用法)。后来听老师讲解后,该题中用下标法写起来会更简洁,此题用指针稍显繁杂,也容易写错,

    因此很有可能就是指针部分写的不够熟悉,导致算法不对,答案全错

  • 2.思路不同:听了老师的讲解,思路大致是相同的,我也考虑到了开辟新数组来存储。

    思路相对不同的地方是:老师的代码是以a,b数组的扫描均未完成的情况来循环,另外,a,b任意一个数组一旦扫描完成,就直接进行剩余元素赋值的操作。

    而我的则是以c数组的赋值为循环,然后在循环中,再对这三种情况,进行分类判断。而老师的思路写起来会更为简单一些。

  • 3.动态申请及其释放意识不强,掌握不熟:一开始对动态内存申请还不是太熟悉,就直接给c数组定义了一个比较大的范围。听完讲解后才意识到,此时应该应用动态申请,

    并且最后要记 得free,对free操作也仍不够娴熟

C博客作业05--2019-指针的更多相关文章

  1. C语言l博客作业05

    问题 回答 这个作业属于哪个课程 C语言程序设计ll 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-2/homework/9830 我在这 ...

  2. C语言博客作业05——指针

    1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量 1.2.1学习体会 可能因为之前数组那块儿的作业拖得太久了,以至于我觉得指针学的好快,还没反应过来就教完了,然后一开始做题的时候,就是一脸 ...

  3. C语言I博客作业05

    内容 答案 这个作业属于哪个课程 C语言程序设计II 这个作业要求在哪里 C语言I作业05 我在这个课程的目标是 更熟练的运用编译函数问题 这个作业在哪个具体方面帮助我实现目标 PTA实验作业 参考文 ...

  4. C语言|博客作业05

    这个作业属于哪个课程 C语言程序设计II 这个作业的要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-1/homework/9825 我在这个课程的 ...

  5. c语言1博客作业05

    一.本周作业头 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-3/homework/9831 我 ...

  6. C语言Ⅰ博客作业05

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-3/homework/9827 我在这个课程的目 ...

  7. C语言博客作业05

    这个作业属于哪个课程 C语言程序设计II 这个作业要求在那里 https://edu.cnblogs.com/campus/zswxy/CST2019-3/homework/9827 我在这个课程的目 ...

  8. C博客作业05—指针

    1.本章学习总结 1.1思维导图 1.2本章学习体会及代码量学习体会 1.2.1 学习体会 理解了指针在代码中的使用方法,学会使用指针进行参数操作 学会了结构体的定义方式与结构体的使用 经过持续一个周 ...

  9. DS博客作业05——树

    1.本周学习总结 1.1思维导图 1.2学习体会 学习:相比于之前的数据结构,树多了很多性质,相应的也多了很多计算题,不得不说,专有名词也是颇多.觉得树最独特的地方就是它的兄弟.孩子结点,用以组成了它 ...

  10. DS博客作业05—树

    1.本周学习总结 1.1思维导图 1.2学习体会 本周学习了树的相关知识,了解了树结构体的应用和基本操作 学习了二叉树的遍历,创建以及哈夫曼树的相关操作 通过树的构建等操作熟练了递归的使用 2.PTA ...

随机推荐

  1. MAC配置JAVA环境变量

    一.下载安装文件 地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html jdk-8u144-macosx-x64. ...

  2. [考试反思]1010csp-s模拟测试67:摸索

    嗯...所谓RP守恒? 仍然延续着好一场烂一场的规律. 虽说我也想打破这个规律,但是并不想在考烂之后打破这个规律.(因为下一场要考好???) 我也不知道我现在是什么状态,相较于前一阶段有所提升(第一鸡 ...

  3. [考试反思]0825NOIP模拟测试30:没落

    AB卷,15人. Lrefrain rank#1 179 skyh rank#2 122 116 108 54 42虽说还是不怎么样,但是有好转的迹象. 开卷审题,T1是个(假)期望,感觉也许还可做. ...

  4. 基于 Jenkins Pipeline 自动化部署

    最近在公司推行Docker Swarm集群的过程中,需要用到Jenkins来做自动化部署,Jenkins实现自动化部署有很多种方案,可以直接在jenkins页面写Job,把一些操作和脚本都通过页面设置 ...

  5. 使用Typescript重构axios(三十二)——写在最后面(总结)

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  6. jquery 路径动画贝塞尔动画

    jquery 路径动画贝塞尔动画 <pre><!DOCTYPE html><!DOCTYPE html><html> <head> < ...

  7. 关于github 新工程上传代码 git 命令

    1.git init // 初始化git文件 2.git add . //添加上传全部文件 "."代表全部 3.git remote add origin  git····//gi ...

  8. linux环境中,两个不同网段的机器互通

    linux环境中,两个不同网段的机器互通   人评论3690人阅读2019-11-18 14:50:21   环境如下:   host1 单网卡 eth0 172.24.100.15/16   hos ...

  9. 2019CSP游记

    \(CSP2019\)游记 写在前面 考完,终于深刻地认识到省一似乎和我想象的真不是一个难度.也罢,不然为什么\(NOIP\)改了名还是这么有含金量. 考前一天和一群同学们嚷嚷着要去吃散伙饭,说没拿到 ...

  10. [LC]530题 二叉搜索树的最小绝对差

    ①题目 给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值. 示例 : 输入: 1   \   3  / 2 输出:1 解释:最小绝对差为1,其中 2 和 1 的差的绝对值为 ...