展示PTA总分
1.本章学习总结
1.1 学习内容总结
1、关于指针是什么
·指针是用来存放地址的变量
·C语言中把专门用来存放变量的地址的变量称为“指针变量”,简称指针
·如果一个指针变量的值是另一个变量的地址,就称该指针变量指向那个变量。
例如:
定义一个指针变量p
定义输入整型x
令p=&x
p则为x的地址,而*p为x的内容
称p指向x
2、指针包含些什么
·一级指针
(1)指针变量的定义
一般形式:
类型名 *指针变量名;
而指针声明符*
在定义指针变量时被使用,说明被定义的那个变量是指针
注:定义多个指针变量时,每一个指针变量前面都必须加上*
。
(2)关于指针,数组和地址间的关系
在访问内存中,指针和数组几乎是相同的。
例如:
int a[100],*p;
假设1000是a[0]的地址,那么1000也是a的基地址。
所以
p=a;
p=&a[0];
这两条语句是等价的。
而就有了:
指针 | 内存地址 | 内存单元 | 数组元素 |
---|---|---|---|
p | 1000 | a[0] | |
p+1 | 1002 | a[1] | |
p+2 | 1004 | a[2] | |
··· | ··· | a[i] |
数组名可以使用指针形式,而指针变量也可以转换为数组形式
区别:
指针是以地址作为值的变量,而数组a是指针常量,不是变量。所以,
a=p
a++
a+=2
这些说法都是错误的!
·二级指针
(1)内容定义
二级指针即为指向指针的指针,一般定义为:
类型名 **变量名
来看看这个:
int a=10;
int *p=&a;
int **pp=&p;
此时,p指向a,而pp又指向p。
所以,pp和&p值相等,而p又与&a值相等。即:a,*p,**p的值是相等的。
(2)二维数组的指针形式
二维数组可以理解为是数组元素为一维数组的一维数组。
如有一个二维数组a[][],则可以说a是一个二级指针。
在书中也有列出了二维数组中的指针等价关系。
①行指针:
一般定义形式:
int (*p)[n];
行指针P是行地址性质的指针。
行指针可以和数组名交换使用,若有
int a[4][5]
int (*p)[5]
a=p;
则有a[0][0]=p[0][0].
②列指针:
形式:
int a[4][4],*p;
p=a;
则表示P是列指针。
·字符指针
字符指针是一个指向该字符串首字符的指针常量
例如:
char *p="string";
printf("%s",p);
以%s的格式输出字符串时,作为输出参数,指针p的值为地址,从首地址所指定单元开始连续输出其中的内容,直到遇到‘ ’。
输出参数给出起始位置,' '用来控制结束。
而类似于p+2,P+3,则就表示,从字符串的第二个,第三个字符开始输出。
·用指针实现内存动态分配
1、动态内存分配的步骤
①了解需要多少内存空间
②利用动态分配函数来分配所需要的储存空间
③使指针指向获得的内存空间
④使用完毕后,释放空间
2、动态内存分配函数
①malloc()
函数原型:
void *malloc (unsigned size)
功能:在具体使用中,需要将malloc()的返回值转换为特定指针类型,赋给一个指针,如:
p=(int *)malloc(n*sizeof(int))
注:不要越界使用,大小在分配后是确定的。
②calloc()
函数原型:
void *calloc(unsigned n,unsigned size)
功能:在分配完n个连续空间后还把存储块里全部初始化为0。申请成功后,则返回一个指向被分配内存空间的起始地址的指针;不成功,则返回NULL(0)。
③动态存储释放函数free()
函数原型:
void free(void *Ptr)
功能:释放申请到的动态内存空间。
3、指针怎么用
(1)指针的基本运算
①取地址运算和间接访问运算
·单目运算符&用于给出变量的地址。如:
int *
p,a=3
p=&a;
当p指向a时,*
p和a访问同一个储存单元。即*
p=a。
关于值加1
表达式
*p
=*p+1
、++*p
、(*p
)++
都为p所指向的变量的值+1。
②赋值运算
指针被定义并赋值后,就可以如同其他类型变量一样进行赋值运算
int a=3,``*p1``,``*p2``
p1=&a;
p2=p1;
此时,*p1
,*p2
,a都访问同一个储存单元,它们的值都一样
注:·指针只有在被赋值以后才能被正确使用
·只能将一个指针的值赋给另一个相同类型的指针。
③指针变量的初始化
指针变量在定义后也要先赋值再引用
如:
p1=&a
p2=p1
注意:
1、*
只表示该变量是个指针变量,既不是乘法也不是间接访问符
2、在初始化之前必须已经定义,因为变量只有在定义后才被分配储存单元,它的地址才能赋给指针变量
3、已经初始化了的指针变量可以给另一个指针变量作初始化值。
4、不能用数字作为指针变量的初值,但可以初始化为空指针
例如:
int *p=1000 是错误的,p所指向的一个地址
int *p=0 是正确的,初始化为空指针
5、指针变量定义时的数据类型和它所指向的目标变量的数据类型必须一致,因为不同的数据类型所占用的储存单元的字节数不同
6、关于空指针的作用:
如果没有对指针进行初始化,这个指针变量就会变成没有指向的危险野指针。
(2)指针作为函数的参数
①void,无返回值时
这就不得不提到书本的例题了
代码如下:
运行结果如下:
可以看出只有swap2完成了数值交换,是为什么呢?
·在swap1中,使用的是普通变量调用,也就是值调用。确实在调用函数中,他们的数值交换了。但是,当返回主函数时,函数swap1()中定义的变量都销毁了,主函数中a,b的值没有任何改变。
·在swap2中,实参是指针变量pa和pb,也就是a和b的地址。函数调用时,形参px和py获得了pa和pb传递进来的地址。函数中,改变*px
的值,就改变了该储存单元的内容。返回主调函数后,由于a代表的单元内容发生了变化,a的值就改变了,从而达到了交换的目的。
·在swap3中,直接交换了形参px和py的值,形参px和py的改变不会影响实参pa和pb。
②指针做函数返回值
来看看PTA上的例题:
这是一道查找子串的题目,题目调用了指针类型的函数。
而这个时候,我们必须具有返回值,并且返回的必须为地址。
(3)关于常用字符串处理函数
一些输入输出函数:
函数名 | 作用 | 形式 | 注意事项 |
---|---|---|---|
scanf() | 字符串输入 | scanf("%s",s) | 遇回车或空格输入结束,并自动加入' ' |
gets() | 字符串输入 | gets(s) | 允许带空格,有返回值,输入失败则返回NULL |
printf() | 字符串输出 | printf("%s",s) | 输出遇' '结束 |
puts() | 字符串输出 | puts(s) | 输出字符串后会自动换行 |
在系统头文件string.h中的函数:
函数名 | 作用 | 形式 | 注意事项 |
---|---|---|---|
strcpy() | 把字符串s2复制到s1 | strcpy(s1,s2) | s2遇到' '后停止,s1必须是基地址 |
strcat() | 将字符串s2连接到s1后面 | strcat(s1,s2) | s1的长度要足够大 |
strcmp() | 比较字符串s1,s2的大小 | strcmp(s1,s2) | 返回值为比较两者的差 |
>0 | s1大于s2 | ||
<0 | s1小于s2 | ||
=0 | s1等于s2 | ||
strlen() | 计算字符串字符个数 | strlen(s) | 其长度不包括' ' |
1.2 本章学习体会
关于指针的学习,让我对于C语言有了一个更深的领悟。但是二级指针确实让人头大,emmmm,指针题集上的题目我很多都用数组进行答题...眼看着这个学期就要结束了,我确实领会到了计算机这个新世界的风采,但确实也让我苦恼了。我真的觉得每一章的内容都需要去回顾去复习,不然很快就忘了。关于字符串的输入之类的啊,也需要去了解到每一个细节点,比如scanf遇空格回车结束啊之类的。
代码量:
指针题目集:387
2.PTA实验作业
2.1 (指针做函数返回值) 查找指定字符
2.1.1伪代码:
定义op为待查找字符
定义指针str为输入的字符串
定义index为找寻的下标
申请动态内存空间
输入字符op
缓冲换行符
自定义SearchIndex()函数
if index=-1 then
输出 not found
else
输出 index=找寻的下标
释放动态内存
int SearchIndex(char* str, char op)
定义i=0
定义index=-1
while 字符串不为0和
时
if 查找的字符与str[i]相等 then
index=i
i++
continue
i++
返回index
2.1.2
代码截图:
2.1.3 总结本题的知识点
1、掌握定义指针变量后要申请动态内存空间
str = (char*)malloc(N * sizeof(char));
不同类型变量,即把char进行修改
如若为整型,则:
str = (int*)malloc(N * sizeof(int));
2、注意释放动态内存空间
3、注意对i进行自增
4、注意0与NULL,返回 NULL 和 返回 0 是完全等价的。
2.1.4 PTA提交列表及说明
部分正确:刚开始就误打误撞的对了一个测试点?
段错误:
1、对于输入str,VS总是会提醒我没有初始化。我觉得很奇怪,后来问了一下同学,才知道要对str申请内存空间,在定义指针str后,它并不知道它所指向的地址是哪里,用malloc或calloc申请内存空间的首地址之后,str才会有指向。如若定义数组,系统才会自动为str申请内存空间。嗯...直到现在我才真正懂得了malloc和calloc的真正用法含义...
2、关于换行符。刚开始,我只能输入需要查找的字符,无法输入字符串。fgets会吸收换行符,所以我需要加入scanf("
")来消除换行符。
部分正确:主要错误的测试点是index=0,刚开始,如果index的返回值是NULL,则就输出not found。但我忽略掉的是返回NULL和返回0是完全等价的,则当index=0时,他也会输出not found。后来我便用-1进行替换。
2.1 藏尾诗
2.1.1
伪代码:
定义数组str1用于放入诗句
定义数组str2用于存放诗句最后汉字
定义整型row为诗句句子数量
定义整型len为字符串长度
对i,row进行初始化
while(诗句的输入存放于str1)
计算字符串长度
使诗句最后汉字存放于str2中
str2[i++] = str1[len - 2];
str2[i++] = str1[len - 1];
row自增
if row 大于等于4 then
break;
令str2[i]=0,防止输出泛滥
输出str2
2.1.2 代码截图
2.1.3 总结本题的知识点
1、关于汉字有两个字节的深刻理解
2、用i++和len-1,len-2为一个汉字申请到了两个字节
3、在str2结尾处添加结束符
2.1.4 PTA提交列表及说明
·答案错误:
1 虽然提交列表只有两行,但是我在VS上调试了挺久。刚开始,我没有真正理解一个汉字占两个字节的含义。我只是让他的输入拥有两个字节,可是,在放入一个新数组中我只给了每个汉字一个字节。后来,给予两个字节之后就能输出了
2 没有给予结束符,得到乱码
2.1 合并两个有序数组
2.1.1 伪代码
定义整型数组a,b
定义m,n分别表示a,b数组的长度
分别为a,b申请动态内存空间
将数据输入数组a中
将数据输入数组b中
函数merge()使a,b合并到a
输出数组a
释放申请的动态内存空间
void merge(int* a, int m, int* b, int n)
定义新数组c
为数组c申请动态内存空间
for i=j=k=0 to i<m,j<n
if a[i]小于b[j] then
c[k++]=a[i++]
else
c[k++]=b[j++]
while i小于m 即当b数组已经结束
c[k++]=a[i++]
while j小于n 即当a数组已经结束
c[k++]=b[j++]
for i=0 to m+n
将c数组内容移至a数组
释放申请的动态内存空间
2.1.2 代码截图
2.1.3 总结本题的知识点
1、可在两个数组之间进行判断,较小值直接输入另一个数组中
2、在定义完指针数组之后要记得申请动态内存空间
2.1.4 PTA提交列表及说明
部分正确:刚开始我使用的是,将两个数组合并到一个数组之后再使用冒泡法进行排序,但是当数据太多时,循环太多次就造成超时。
段错误:我忘记为定义的指针申请动态内存空间
3.阅读代码
题目:
输入输出样例:
代码:
学习到的内容:
1、关于memset()函数,它主要形式为memset(a,n,sizeof(a)),所要表达的是给a这个数组的全部元素赋初值。
2、用一个取余的方式和循环来判断要出局的人的位置
3、将所有人的名字认为是一个字符串存入数组中
4、用一个out数组,使pos不断发生变化,最后直接按变化了的pos使name数组中的名字按出局顺序输出。