这个作业属于哪个课程 | c语言程序设计 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/zswxy/software-engineering-class1-2018/homework/2889 |
我在这个课程的目标是 | 指针得使用和返回 |
这个作业在那个具体方面帮助我实现目标 | 用指针解决函数问题 |
参考文献 | c语言程序设计 |
6-1 求两数平方根之和
函数fun的功能是:求两数平方根之和,作为函数值返回。例如:输入12和20,输出结果是:y = 7.936238。
函数接口定义:
double fun (double *a, double *b);
其中 a和 b是用户传入的参数。函数求 a指针和b 指针所指的两个数的平方根之和,并返回和。
裁判测试程序样例:
#include<stdio.h>
#include <math.h>
double fun (double *a, double *b);
int main ( )
{ double a, b, y;
scanf ("%lf%lf", &a, &b );
y=fun(&a, &b); printf ("y=%.2f
", y );
return 0;
}
/* 请在这里填写答案 */
输入样例:
12 20
输出样例:
y=7.94
实验代码:
double fun(double*a,double*b)
{
double sum;
sum=sqrt(*a)+sqrt(*b);
return sum;
}
错误截图:
解决方法:
定义指针用,隔开
运行结果:
流程图:
7-1 利用指针返回多个函数值 (30 分)
读入n个整数,调用max_min()函数求这n个数中的最大值和最小值。
输入格式:
输入有两行: 第一行是n值; 第二行是n个数。
输出格式:
输出最大值和最小值。
输入样出一组输入。例如:
5
8 92 0 3
输出样例
在这里给出相应的输出。例如:
max = 1
min = 0
实验代码:
#include<stdio.h>
void max_min(int n, int *a);
int main()
{
int n;
scanf("%d", &n);
int a[n];
for(int i = 0;i < n;i++)
{
scanf("%d", (a + i));
}
max_min(n, a);
return 0;
}
void max_min(int n, int *a)
{
int t;
for(int i = 0;i < n - 1;i++)
{
for(int j = 0;j < n - i - 1;j++)
{
if(*(a + j) < *(a + j + 1))
{
t = *(a + j + 1);
*(a + j + 1) = *(a + j);
*(a + j)= t;
}
}
}
printf("max = %d
", *(a));
printf("min = %d
", *(a + n - 1));
}
复制代码
设计思路:
1)定义函数max_min并输入整数个数N和数组a[n]
- 利用函数max和min将数据首位的值赋给max和min并输出最大值和最小值
3)将i的值赋为0并判断i是否小于n是则进入下一个循环否则输出最大值和最小值
遇到的问题及其解决方法:
1)问题1:for循环的嵌套出错
解决办法:严格控制代码格式,注意大括号的位置,在本子上自己用笔运算一下再运行
为一维数组输入10个整数;将其中最小的数与第一个数对换,将最大的数与最后一个数对换;输出数组元素。。
函数接口定义:
void input(int arr,int n);
void max_min(int arr,int n);
void output(int *arr,int n);
7-1
三个函数中的 arr和n 都是用户传入的参数。n 是元素个数。
input函数的功能是输入 n个元素存到指针arr所指向的一维数组中。
max_min函数的功能是求指针arr所指向的一维数组中的最大值和最小值,其中最小的数与第一个数对换,将最大的数与最后一个数对换。
output函数的功能是在一行中输出数组元素,每个元素输出占3列。
裁判测试程序样例:
include<stdio.h>
void input(int arr,int n);
void max_min(int arr,int n);
void output(int *arr,int n);
int main()
{ int a[10];
input(a,10);
max_min(a,10);
output(a,10);
return 0;
}
/* 请在这里填写答案 */
输入样例:
5 1 4 8 2 3 9 5 12 7
输出样例:
1 5 4 8 2 3 9 5 7 12
实验代码:
void input(int arr,int n)
{
for(int i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
}
void max_min(int arr,int n)
{
int i,max,min,p;
for(i=1;i<n;i++)
{
if(arr[i]>arr[max])
max=i;
if(arr[i]<arr[min])
min=i;
}
temp=arr[max];
arr[max]=arr[9];
arr[9]=p;
temp=arr[0];
arr[0]=arr[min];
arr[min]=p;
}
void output(int *arr,int n)
{
for(int i=0;i<n;i++)
{
printf("%3d",arr[i]);
}
}
运行结果:
流程图:
学习总结:
周/日期 | 这周所花的时间 | 代码行 | 学到的知识点简介 | 目前比较迷惑的问题 |
---|---|---|---|---|
3.3-3.9 | 3h | 32 | 如何在Dev | C++中写入文件并打开执行命令 |
3.10-3.16 | 5h | 75 | 用指针打开文件 | 二维数组 |
3.17-3.23 | 6h | 112 | 选择排序 | 冒泡排序的方法 |
3.24-3.30 | 5h | 97 | 冒泡排序以及字符串使用 | 冒泡排序与选择排序的区 |
4.2-4.6 | 3h | 40 | 指针返回多个函数的值 | *和&的变化和指针传变量地址的问题 |
学习心德:
越来越难了,感觉要花很多时间了
为什么要用指针?
作者:Tim Shen
链接:https://www.zhihu.com/question/26623283/answer/33553948
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
0)史前早期的CPU(也许并没有真正的实现)并不如今天的强大,内存读写的指令可能只有“从*常数*0x1234地址处读入1字节到寄存器a”,或者“把寄存器b的值写入*常数*地址0x5678这个地方”。那个时候没有变量这一说,所有的内存读写都得指定好常数,也就是得把具体的数字(也称为字面量,literal)写死在程序里。换言之,你如果想清空100字节的内存,而每条指令只能对内存中某一个字节进行写入,那就得写100条指令。随着要处理的数据的膨胀,程序也得跟着膨胀,而这是不可接受的。
1)流程跳转为了解决这个问题,人们发明了控制流程的指令,比如“如果寄存器c的值为0,则略过下一条指令”和“无条件跳转到首地址为0x9012”的地方,从那个地方继续运行”。注意,指令本身也是编码成字节存在内存里的,这就是冯诺伊曼机器最优雅的地方。这时候我们可以写出循环了(这里不展开,感觉没必要)。
2)自修改程序问题并没有解决,因为就算有了循环,整个程序还是只能写常量,所以如果想要对不同的内存块清零,只能写不同的指令。但是人是很聪明的。利用“指令本身也是编码成字节存在内存里”这个特征,我们可以通过修改内存来修改指令,继而修改行为。举例来说,在0x3454处存了一条指令,这条指令叫做“把0x5678开始的一字节清零”。比方说这条指令占用了三个字节,第一个字节告诉CPU这是一条清零指令,后两个字节(0x3455和0x3456)存了一个表示地址的整数,告诉CPU到底要把哪个字节清零。显然,这个整数会和0x5678有关,而且大多情况就是0x5678。现在,要是CPU在某处执行了一句“把起始地址为0x3455的那个2字节数自增1”,那实际上0x3454处的指令就变成了“把0x5679开始的一字节清零”!看到希望了么,我们可以写一个指令,然后不断修改这个指令,再加上流程控制的指令产生一个循环,就能用一段固定长度(注意,代码内容随着执行并不固定)的代码清零任意指定的一段内存块!这叫做“自修改程序”。
3)间接寻址后来的事情就很简单了。编写这种自修改程序极容易出错,因为稍微改错一个地方指令就全改乱了(比如在上例中如果把0x3454中的数字给改了,就完全变成了另一条指令),所以人们再次发明新的工具,叫间接寻址。所以有了这样的指令“把寄存器a存的数字当成地址,取出该地址处的字节放到寄存器b里”和“把寄存器a存的数字当成地址,把寄存器b的字节写入到该地址处”。回到自修改程序的那个例子里,我们可以把“把0x5678开始的一字节清零”换成:“把寄存器b设为0”“把0x5678这个数字写到0x1234处”“读入0x1234的数字到寄存器a”“把寄存器a存的数字(此处即0x5678)当成地址,把寄存器b(此处为0)的字节写入到该地址处”这样实现虽然看起来费事,但是总算得到了等价的功能。另外,我们以后只需要读写0x1234这个内存就能达到改变行为的目的,而不要冒险去修改指令本身了。换言之,指令本身被固化,其行为更加稳定。今天,代码虽然也在内存里,也编码成了一个个字节,但是一般不和数据放在一起,而且一般执行的时候是只读的。假设程序员无限聪明(当然这种好事从来就没有发生过:),写的代码从来不出错,那么间接寻址是没有必要的,因为直接写自修改程序就行了。间接寻址没有增加任何新的功能,这点不像跳转指令。
4)指针哦,现在解释指针就很简单了,指针就是间接寻址例子里面那个0x1234的内存块。它存了一片地址,而指针解引用(比如*p)就对应的是间接寻址读写的指令了。所以说到最后,“为什么要有指针的”就可以化成“为什么要有间接寻址”,问题基本等价于“为什么不直接使用自修改程序”了。