0.展示PTA总分
1.本章学习总结
1.1学习内容总结
指针变量的定义
类型名: *指针变量名 例如: int *p;//定义一个整型变量p,指向整型变量;
指针和数组的赋值与初始化
一般情况下,数组的地址不能修改,内容可以修改;而指针的内容可以修改,指针指向的内容也可以修改,但这之前要为指针初始化。 如: int p[5]; p=p+1; //错误 而p[0]=1; //正确 // int *p; p=p+1; //正确 p[0]=1;//错误,指针没有初始化; // int i; int *p=&i; p[0]=1;//正确 对于字符指针还有比较特殊的情况。 如: char * p="abc"; p[0]='d';//错误
指针做循环变量做法
例如:对数组元素求和 int a[100]; int *p; int sum=0; p=a; for(p=a;p<=&a[99];p++) { sum+=*p; } 在循环中,指针变量p的初值是数组a的基地址,P连续取值&a[0],&a[1],…&a[99]。
字符串指针如何表示字符串
- 对指向字符变量的指针变量应赋予该字符变量的地址。
例如: char c, *p=&c;//表示p是一个指向字符变量c的指针变量。 char *s="apple";//表示s是一个指向字符串的指针变量。把字符串的首地址赋予s。
- 用字符串指针指向一个字符串。
例如:
#include <stdio.h> int main(){ char *string = "I love China!"; printf("%s\n", string); return 0; }
动态内存分配
- (1)函数malloc()
原型:void* malloc(unsigned size); 在内存的动态存储区中分配一块长度为size字节的连续区域,参数size为需要内存空间的长度,返回该区域的首地址. 函数malloc不能初始化所分配的内存空间,而函数calloc能.如果由malloc()函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之, 如果这部分内存曾经被分配过,则其中可能遗留有各种各样的数据.也就是说,使用malloc()函数的程序开始时能正常进行,但经过一段时间可能会出现问题.
- (2)函数calloc()
原型:void* calloc(size_t numElements, size_t sizeOfElement); 与malloc相似,参数sizeOfElement为申请地址的单位元素长度,numElements为元素个数,即在内存中申请numElements*sizeOfElement字节大小的连续地址空间. 函数calloc() 会将所分配的内存空间中的每一位都初始化为零,如果是字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;如果是实型数据分配内存,则这些元素会被初始化为浮点型的零.
- (3)函数free()
原型:void free(void *ptr); free之后如果还有这块内存地址的话,此时这块内存归还给了系统,但是还是可以对其进行操作。里面的值短暂的会保留。free之后,申请内存的那个指针就会变成野指针,有时候会出现野指针错误; 所以尽量在操作之后:将指针置为NULL 注意:申请和释放是一起的,所以程序是不能进行多次free同一个指针,否则程序会出错。
指针数组及其应用
- 非常容易混淆的两个概念:“指针数组”与“数组指针”
指针数组:表示的是一个数组,数组中每一个变量都是指针型变量;
数组指针:表示的是一个指针类型的变量,这个指针变量指向的是一个数组。 数组指针
定义int (*)data[10] = NULL;//定义了一个指向长度为10的int数组(int [10])的指针.
- 指针数组:
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,数组名为p,该p数组中有n个元素,分别为p[0]、p[1]、……、p[n-1],每个元素均为指向int类型的指针变量(可以理解成(int *) p[n]),即元素的值为地址。
指针数组应用: 例:查找奥运五环色的位置,用指针数组实现 #include<stdio.h> #include<string.h> int main() { int i; char *color[5]={"red","blue","green","black","yellow"}; char str[20]; scanf("%s",str); for(i=0;i<5;i++) if(strcmp(str,color[i])==0) break; if(i<5) printf("position:%d\n",i+1); else printf("Not Found\n"); return 0; }
二级指针、行指针
- 二级指针
定义:类型名 **变量名; 例如: int a=10; int *p=&a; int **pp=&p; 一级指针p指向整型变量a,二级指针pp指向一级指针p。由于p指向a,所以p和&a的值一样,a和*p代表同一个单元;由于pp指向p,所以pp和&p的值一样,pp和**p代表同一个单元
- 行指针
定义:int (*p)[3]; *(p+i);//即a[i],第i行数组名,指向第i行0列的int型元素 *(p+i)+j;//指向第i行j列的int型元素 *(*(p+i)+j);//取出第i行j列的内容
函数返回值为指针
- 使用指针作为函数参数返回多个值的示例
-运行结果
1.2本章学习体会
- 本章学习了指针,包括数组指针,指针数组,字符指针,一级、二级指针等重要内容,内容很多,相对来说也比较难,知识点抽象不易理解,做题无从下手。但是指针是学习C语言最重要的部分,务必要掌握,不能急躁,先理解它的概念,之后熟悉它的格式以及使用方法,多打代码练习。
代码量有1000以上。
2.PTA实验作业
2.1题目7-2 藏尾诗
2.1.1伪代码
for i=0 to N 输入字符串 动态分配:p[i]=(char*)malloc(sizeof(str)+1) 将输入的字符串复制到p[i] end for for i=0 to N 求字符数组p[i]的长度 输出最后一个字组成的字符串 end for
2.1.2代码截图
2.1.3总结本题知识点
动态分配:p[i]=(char*)malloc(sizeof(str)+1) 将输入的字符串复制到p[i]:strcpy(p[i],str) 求字符数组p[i]的长度:len=strlen(p[i])+1 输出最后一个字组成的字符串:printf("%s",p[i]+len-2)
2.1.4PTA提交列表及说明
答案错误:一开始用fgets输入字符串,后来改为用fets输入,还是答案错误。 答案错误:输出字符串的时候没有减去2。 格式错误:刚开始用puts循环输出 答案错误:改为用printf循环输出,写成了%c答案错误,再改为%s 格式错误:在printf()里面加上了\n
2.2题目6-10 填充矩阵
2.2.1伪代码
for i=0 to n for j=0 to n if(是副对角线上的元素) *(p[i]+j=1; end if if(是副对角线下方的元素) *(p[i]+j=2; end if if(是副对角线上方的元素) *(p[i]+j=3; end if end for end for
2.2.2代码截图
2.2.3总结本题知识点
副对角线上的元素:(i+j)==n-1 副对角线下方的元素:(i+j)>n-1 副对角线上方的元素:(i+j)<n-1 取出第i行j列的内容:*(p[i]+j)
2.2.4PTA提交列表及说明
运行超时:不知道哪里错了,试试在每个if语句后面加个break,还是一样的结果。 运行超时:一开始写的是*(*(p+i)+j),后来发现可以改成*(p[i]+j)。 运行超时:找了很久发现if语句里面i+j没有加上括号,改成if((i+j)==n-1) 答案错误:副对角线上方下方的元素是2还是3搞混了 答案错误:写成了(i+j)==n,运行发现1都不在副对角线上,就改成(i+j)==n-1
2.3题目6-6 查找子串
2.3.1伪代码
i=0,j=1; while(s[i]) if(在字符串中找到子串的第一个字符) while(s[i+j]==t[j]&&t[j]!='\0') j++; end while if(t[j]=='\0') 返回返回子串t在s中的首地址 end if end if i++; end while
2.3.2代码截图
2.3.3总结本题知识点
如果在字符串中找到子串的第一个字符,则开始从当前位置扫描子串 if(s[i]==t[0] { while(s[i+j]==t[j]&&t[j]!='\0') j++; } 返回子串t在s中的首地址:return s+i;
2.3.4PTA提交列表及说明
部分正确:搞不清楚j是从0开始还是从1开始。 部分正确:错误写成当t[j]不等于0时返回子串t在s中的首地址。 部分正确:不知道t在s中的首地址怎么表示。
3.阅读代码
- 代码功能:计算比赛中问题的最大期望值,并能实现找出字典上最小的序列,使预期数目的解决问题最大。
- 代码优点:
使用using namespace std调用命名空间std内定义的所有标识符,这样可以在不同命名空间里,起同样的变量名,防止变量名用尽或者冲突。
调用多个头文件,赋予了调用某些函数的权限,便于进行类型检查,增加程序可读性。
使用多次宏定义,实现了一些简单的函数功能,提升了程序编写的灵活性。
使用typedef定义类型的别名,可以减少错误的发生,而且直观简洁。