C博客作业05--指针
0.展示PTA总分
- 指针:
1.本章学习总结
1.1 学习内容总结
-
指针做循环变量做法:
1.指针所指向的内容为字符型时:通常为*p='\0'但字符串是以fgets函数输入时结束标志则为** p&&p!='\n' 。
2.指针所指向的内容为数字时:前提需知数组长度,通过q<p+n进行结束判断(其中q、p为均为指针,n**为数组长度)。 -
字符指针如何表示字符串:
char* sp = "point";
printf("%s", sp);//字符指针sp作为printf的输出参数
- 动态内存分配:此部分内容主要有4种函数malloc、calloc、realloc、free。
1.malloc- malloc()函数会向堆中申请一片连续的可用内存空间。若申请成功,返回指向这片内存空间的指针;若失败,则会返回NULL。所以我们在用malloc()函数开辟动态内存之后,一定要判断函数返回值是否为NULL。注意:malloc()返回的是void*,所以在分配内存时必须强制转换为所需指针类型。
//示例
int *p = NULL;
int n = 0;//所需内存大小
scanf("%d", &n);
p = (int*)malloc(sizeof(int) * n);
2.calloc
* 与malloc()函数的区别只在于:calloc()函数会在返回地址之前将所申请的内存空间中的每个字节都初始化为0。calloc()函数功能是动态分配n个大小(字节长度)为size的内存空间。
//示例
int *p = NULL;
int n = 0;//所需内存大小
scanf("%d", &n);
p = (int*)calloc(n,sizeof(int));
3.realloc
* 当分配的内存大小不合适时(太大或太小),此时可通过realloc()进行对动态开辟内存大小的调整(既可以往大调整, 也可以往小了调整)。若调整成功, 返回值为调整大小后内存的起始位置, 若失败(当没有内存可以分配时), 则返回NULL, 所以还是要对返回值判空。
//示例
int *p = NULL;
p = (int*)malloc(20);
p=(int*)realloc(p,40);//调整内存
4.free
* 在堆中申请的内存空间不会自动释放内存,如果我们不手动释放,只有在程序运行结束时才会释放, 这样就可能会造成内存泄漏, 即堆中这片内存中的数据已经不再使用, 但它一直占着这片空间,(通俗说就是就是占着茅坑不拉屎), 所以当我们申请的动态内存不再使用时 ,一定要及时释放。
//示例
int *p=NULL;
p=(int*)malloc(20);
free(p);//释放内存
- 指针数组及其应用:
- 定义:int*a[10];其类似于二位数组,但列数未知,当我们进行赋值时,同样需要进行动态内存分配。
//示例
for(i = 0; i < 10; i++)
{
a[i] = (char *)malloc(sizeof(int)*10);//分配内存
scanf("%d", a[i]);
}
2. 应用见PTA题目:<a href="https://pintia.cn/problem-sets/1192644021711056896/problems/1196345664248123398" target="_blank">7-10 6-8 计算最长的字符串长度</a>
题目相关内容截图:
- 二级指针、行指针:
1.二级指针:定义:int **p;其类似于二维数组。可以写成p[][]形式。对于 **p,*p表示的是 地址 ,**p才表示 内容 ,可借助二位数组进行理解。
2.行指针:行指针是指向数组的指针,定义:int a(*p)[5];(相当于int a[][5]);p即为行的地址。其中:*p=a[0],*(p+1)=a[1],*p+a[0][1]··· - 函数返回值为指针:
- 函数声明:int*fun();此函数所返回的值即为一个地址。需注意的是:函数运行结束后会销毁在它内部定义的所有局部数据,函数返回的指针请尽量不要指向这些数据,它们在后续使用过程中可能会引发运行时错误。
//示例
#include <stdio.h>
int* fun()
{
int n = 100;
return &n;
}
int main()
{
int* p, n;
p = fun();
scanf("%d", &n);
printf("%d\n", *p-n);
return 0;
}
- 输入数据100时,结果2095176,为异常数据,说明返回了一个异常地址。
1.2 本章学习体会
刚刚开始时,的确觉得本章内容较难,有些难理解。但慢慢的跟数组联系上,并刷了一些题目之后,就感觉难度就降了好多。怎么说呢,可能是熟能生巧吧。我个人感觉其实只要愿意去学,去做题,该克服的困难总会克服。
2.PTA实验作业
2.1 6-9 合并两个有序数组
2.1.1 伪代码
//此题为函数题,以下代码为题目
#include <stdio.h>
#include <stdlib.h>
void printArray(int* arr, int arr_size); /* 打印数组,细节不表 */
void merge(int* a, int m, int* b, int n); /* 合并a和b到a */
int main(int argc, char const *argv[])
{
int m, n, i;
int *a, *b;
scanf("%d %d", &m, &n);
a = (int*)malloc((m + n) * sizeof(int));
for (i = 0; i < m; i++) {
scanf("%d", &a[i]);
}
b = (int*)malloc(n * sizeof(int));
for (i = 0; i < n; i++) {
scanf("%d", &b[i]);
}
merge(a, m, b, n);
printArray(a, m + n);
free(a); free(b);
return 0;
}
//题目结束,以下为伪代码
void merge(int* a, int m, int* b, int n)//函数定义
int i=a数组长度-1;
int j=b数组长度-1;
int max=ab总长度之和-1;
while(i和j均大于0)
{
从两数组末尾开始
if a的数大于b的数
则 a[max]=a的数,同时max自减
否则
a[max]=b的数,同时max自减
end if
}
end while
if b数组还有数没有插入a数组
通过循环 将剩下的数插入a数组
2.1.3 总结本题的知识点
- 学习如何高效的将有序数组进行合并,而不是简单粗暴的合并数组并重新排序。
2.1.4 PTA提交列表及说明
- 说明:
1.部分正确:刚开始的思路就如上说的简单粗暴,而且排序的循环体还写错了。
2.部分正确:在1的基础上写完整了选择法排序。但大数据过不去。
3.部分正确:更改为冒泡排序,大数据仍过不去。
4.编译错误:改用上述伪代码的方法,但是分号忘记打了。
5.全部正确。
2.2 7-4 说反话-加强版
2.2.1 伪代码
for(从字符串末尾字符开始)
if 不是空格
计数器加1
else if 计数器不为0
循环往后输出计数器个数字符
end if
输出空格
计数器归零
end for
2.2.3 总结本题的知识点
- 通过使用单词‘开关’,判断是否有单词并记录单词长度,一举两得。
2.2.4 PTA提交列表及说明
- 说明:
1.编译错误:定义的数组过大,超出范围了。
2.编译错误:同上。
3.内部错误:PTA的问题吧。
4.部分正确:最大句子测试点没过,为50000个单词。我只定义50000发现远远不够。
5.内部错误:PTA问题。
6.全部正确:定义值改为100001。
2.3 实验11-1-6 -指针 指定位置输出字符串
2.3.1 伪代码
//此题为函数题,以下为题目代码
#include <stdio.h>
#define MAXS 10
char *match( char *s, char ch1, char ch2 );
int main()
{
char str[MAXS], ch_start, ch_end, *p;
scanf("%s\n", str);
scanf("%c %c", &ch_start, &ch_end);
p = match(str, ch_start, ch_end);
printf("%s\n", p);
return 0;
}
//题目结束,以下为我的函数伪代码
char* match(char* s, char ch1, char ch2)//函数定义
for(遍历数组)
找到ch1和ch2在数组中第一次出现位置
end for
如果 ch1没找到
则输出换行
结束函数
else if ch2没找到
则从ch1在数组所在位置开始输出
else
从ch1位置到ch2位置输出
end if
返回 ch1在数组中的地址
2.3.3 总结本题的知识点
- 可能数组中有多个字符和启示或终止符相同,此就需要设置开关仅需要第一次出现的位置。
2.3.4 PTA提交列表及说明
- 说明:
1.部分正确:忘了考虑ch2找不到的情况。
2.部分正确:ch1找不到的情况下,输出跟PTA描述有误。
3.部分正确:更改完还是一样的问题。
4.部分正确:测试点取超长长度是过不去。
5.部分正确:改完ch2找不到时输出少一个字符。
6.部分正确:(这个只是又提交了一遍一样的)
7.部分正确:改回4的代码
8.全部正确:发现代码不能处理ch1重复出现情况,增加了是否第一次出现的开关。
3.阅读代码
poj 1972 Dice Stacking
代码截图
- 代码功能:
- 有多组,每组有多个骰子,每个骰子的面由人决定。通过堆积骰子使得相邻骰子的上下面相同。可以旋转骰子使得面向自己所有面之和最大。
- 输入:按顺序为:组数,每组骰子个数,每个骰子每个面的数子。
- 输出:面向的所有面之和的最大值。
- 值得学习地方:
1.for(scanf("%d",&T);T;T--),该句巧妙简化了条件循环的代码。
2.二维数组中通过字母建立面跟数的关系,但这种写法对于目前c好像不能实现。