0.展示PTA总分(0----2)
展示关于“指针题目集”分数截图。
1.本章学习总结(2分)
1.1 学习内容总结
(1) 指针做循环变量做法
#include<stdio.h> void main() { int arr[]={6,4,3,5,8,1}; int len = sizeof(arr); for(int i=0;i<len;i++) { printf("%d\n",arr[i]);//常规遍历方式 } for(int i=0;i<len;i++) { printf("%d\n",*(arr+i));//使用arr指针遍历方式 } int *p_arr=arr; for(int i=0;i<len;i++) { printf("%d\n",*(p_arr+i));//额外使用新指针来遍历数组 printf("%d\n",*p_arr++);//额外使用新指针来遍历数组 } }
(2) 字符指针如何表示字符串
- C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中。字符数组归根结底还是一个数组,当然关于指针和数组的规则同样也适用于字符数组。举一个例子:
#include <stdio.h> #include <string.h> int main(){ char str[] = "asdfghjkl"; char *pstr = str; int len = strlen(str), i; /*使用*(pstr+i)形式*/ for(i=0; i<len; i++){ printf("%c", *(pstr+i)); } printf("\n"); /*使用pstr[i]形式*/ for(i=0; i<len; i++){ printf("%c", pstr[i]); } printf("\n"); /*使用*(str+i)形式*/ for(i=0; i<len; i++){ printf("%c", *(str+i)); } printf("\n"); return 0; }
上面的三种输出形式输出的结果都是一样:asdfghjkl
除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:
char *str = "asdfghjkl";
或者:
char *str; str = "asdfghjkl";
字符串中的所有字符在内存中是连续排列的,str 指向的是字符串的第 0 个字符;我们通常将第 0 个字符的地址称为字符串的首地址。字符串中每个字符的类型都是char,所以 str 的类型也必须是char *。
(3) 动态内存分配
首先,我们应该知道。所有的程序都必须留出足够的内存空间来存储所使用的数据,所以我们常常会预先给程序开辟好内存空间,然后进行操作。例如,我们经常会利用数组来储存我们需要的数据。但是利用数组的时候需要提前设置数组长度。在今后的学习中我们经常会不知道数据大小是多少,如果直接设置一个较大的量大的话会导致空间的浪费,并且,如果数据超过了数组数据类型最大长度的话,也会造成错误。对于传统数组,会遇到这种问题:
int arr[5] ;
- malloc()函数;
对这个数组我们在定义的时候必须给提前开辟好空间。而且在程序运行的过程中,这个开辟的内存空间是一直存在的。除非等到这个函数运行完成,才会将空间释放。
另一个问题就是这个数组在程序中无法被改动。这些问题给我们造成了一些使用上的不方便,所以,C中提供了malloc()函数。 关于malloc()函数。这个函数它接受一个參数:就是所需的内存的字节数。然后malloc()找到可用内存中那一个大小适合的块。在这个过程中,malloc()能够来返回那块内存第一个字节的地址。所以。也就意味了我们能够使用指针来操作。malloc()能够用来返回数组指针、结构指针等等。所以我们须要把返回值的类型指派为适当的类型。当malloc()找不到所需的空间时。它将返回空指针。例如:
int *p; p=(int*)malloc(3*sizeof(int));
在这个程序中,首先开辟了3个int类型的空间,然后把p指向这个空间的位置。在这里的指针是指向第一个int值。并非我们所有开辟的3个int的空间。这就和数组一样,指向数组的指针式指向数组首元素的地址,并非整个数组的元素。所以,在这里我们的操作也和数组是一样的, p[0]就是第一个元素。p[2]就是最后一个元素。 至此。我们就能够掌握到一种声明动态数组的方法。(不要忘记要将该动态内存的首地址进行强制类型转化换成int型并存放在指针p中)
int arr[n]; p=(int *)malloc(n*sizeof(int)); //我们在这里使用的时候要元素个数乘类型字节长度。这样就达到了动态开辟内存空间。
free()函数;
当我们使用malloc()开辟完内存空间以后,我们所要考虑的就是释放内存空间,在这里,C给我们提供了free()函数。free()的參数就是malloc()函数所返回的地址,释放先前malloc()函数所开辟的空间。 如果申请了动态内存而没有及时释放的话,会造成内存的溢出;calloc()函数;
与 malloc() 相比有两个优点:
(1)它把内存分配为给定大小的数组;
(2)它初始化了所分配的内存,所有位都是 0。
int *pNumber = (int*)calloc(75, sizeof(int)); // 分配了包含75个int元素的数组
如果不能分配所请求的内存,返回值就是 NULL。
- relloc()函数;
realloc() 函数可以重用或扩展以前用 malloc()或 calloc()(或者realloc())分配的内存。
realloc()的两个参数:
1)、一个是包含地址的指针,该地址以前由malloc()、colloc()或realloc()返回。
2)、要分配的新内存的字节数。
realloc()函数分配第二个参数指定的内存量,把第一个指针参数引用的、以前分配的内存内容传递到新分配的内存中,传递的内容量是新旧内存中区域较小的那一个。
realloc()函数返回一个指向新内存的void指针,如果分配失败,返回NULL。如果第一个参数是NULL,就分配第二个参数指定的新内存,类似malloc()。
realloc()保存了原内存区域的内容,且保存的量是新旧内存区域中较小的那个。如果新内存区域大于旧内存区域,新增的内存就不会初始化,而是包含垃圾值。
(4) 指针数组及其应用
数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。定义数组时,一定要给出数组名,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。虽然可以认为是一个指针,但你在定义时在数组变量名前面加 * ,这就不是一个常规的数组了,而是指针数组,里面的所有元素都是指针。
#include<stdio.h> void main() { int arr[] = {1,2,3,4,5,6}; //这里的变量名arr里面存放的有该数组的第一个数据的地址也就是arr[0]的地址值 //所以可以认为arr就是该数组的指针 int *p=arr; int *arr[]={p};
(5)二级指针、行指针
- (1)二级指针
指针可以指向一份普通类型的数据,例如 int、double、char 等,也可以指向一份指针类型的数据,例如 int 、double 、char * 等。如果一个指针指向的是另外一个指针,我们就称它为二级指针,或者指向指针的指针。
int a =100; int *p1 = &a; int **p2 = &p1;
指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号*。p1 是一级指针,指向普通类型的数据,定义时有一个*;p2 是二级指针,指向一级指针 p1,定义时有两个*。你想是几级的指针,p前面就加几个*。 * 行指针; 行指针,顾名思义就是指向一行的指针。在二维指针中,行指针用的最多。我们通常把二维指针看成一个行列式,但是它在内存中的排序却是和一维指针一样的。比如组a[2][3]={{1,2,3}{4,5,6}},a是整个数组的首地址,同时也指向第一行元素,即a是一个行指针,它每加1,所指地址移动二维数组的一行,a+1指向第二行元素。对a取*,即*a指向第一行第一个数,*(a+1)指向第二行第一个数,可见,对行指针取值就成了列指针,此时它还是个指针。它每加1,所指地址移动一个元素,*(a+1)+1指向第二行第二个元素,也可以写成a[1]+1。**a(也可写成a[0][0])就是这个二维数组第一行的第一个元素,**(a+1)(也可写成a[1][0])就是第二行的第一个元素,*(*(a+1)+1)(也可写成a[1][1])是第二行的第二个元素。可见,对行指针取2次*就成了某个元素的值了,而不再是地址。
(6)函数返回值为指针
指针可以作为函数的参数传给函数,那么也一定可以作为函数的返回值,返回给调用函数。比如,写一个返回两者之中较长字符串的函数的示例代码:
#include<stdio.h> #include<string.h> char *compare(char *str1,char *str2){ if(strlen(str1)>strlen(str2)){ return str1; }else if(strlen(str1)<strlen(str2)){ return str2; }else{ char *r = "一样长"; return r; } } void main(){ char *str1 = "123"; char *str2 = "1234"; char *r=compare(str1,str2); printf("%s\n",r); } 打印结果:1234
用指针作为函数返回值时需要注意的一点是,函数运行结束后会销毁在它内部定义的所有局部数据,包括局部变量、局部数组和形式参数等,函数返回的指针请尽量不要指向这些临时数据,谁都不能保证这些临时的数据一直有效,它们在后续使用过程中可能会引发运行时错误。
1.2 本章学习体会
之前听说,C语言有两大利器:指针和强制转化。其中指针更是C语言的灵魂。过了指针这一关才算是真正学习了c语言。刚开始接触的时候感觉一脸懵,完全不知道指针的作用是什么。书上的文字描述也比较生涩难懂,一度不知道该如何学习C。直到上课的时候,老师讲指针就像是一个行走的箭头,它会走向你想要的对象的地址,在我脑海里形成了完整的运行图。后来对于二级指针的理解也就更加深刻了。这一部分比较难,学起来也比较吃力,尤其是在自己编写代码的时候,所以可能还是自己没有用足够多的时间在这上面才会这样吧。
时间 | 代码量 |
---|---|
十三周 | 1103 |
十四周 | 1002 |
2.PTA实验作业(7分)
从PTA题目集中选3题你最满意的题目,题目选难度越大,分值越高。每题2分,做如下内容:
2.1 题目名1
2.1.1 伪代码
用代码渲染符号```渲染伪代码。注意:伪代码不是翻译代码,必须是代码+中文文字描述。先介绍数据处理,用哪些变量。
数据处理可以用C语言符号介绍。具体参考看课件!!!
2.1.2 代码截图
贴图展示代码,不要复制。
2.1.3 总结本题的知识点
如下面总结,也可以观看超星视频中每个题目教师的总结做法。
1.掌握数组右移做法
for ( i = n; i > loc; i--)
{
data[i] = data[i-1];//右移
}
2.注意插入位置在边界情况,数组尾或数组头,需要特殊处理
3.注意插入后,数组长度增1
2.1.4 PTA提交列表及说明
截图PTA提交列表,介绍碰到问题及解决办法。如:
提交列表说明:
请按照如下要求说明提交列表,注意必须写明每个错误点,你是怎么解决的。此项没写好,本题0分
1.编译错误:分号忘记打
2.部分正确:测试数据0,格式错误。0测试点输出问题,直接复制PTA解决。
3.部分正确:个位没有解决好
4.答案错误:。。。
5.部分正确:。。。
6.全部正确:。。。
2.2 题目名2
2.2.1 伪代码
2.2.2 代码截图
2.2.3 总结本题的知识点
2.2.4 PTA提交列表及说明
2.3 题目名3
2.3.1 伪代码
2.3.2 代码截图
2.3.3 总结本题的知识点
2.3.4 PTA提交列表及说明
3.阅读代码(-2--1分)
找一份优秀代码,和数组相关,理解代码功能,并讲出你所选代码优点及可以学习地方。参考网站:
ACM题解
leecode面试刷题网站,找简单题目阅读分析。
其中字符串题目