一.递归
? 程序调用自身的编程技巧称为递归。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小
1.递归的两个必要条件 (1)存在限制条件,当满足这个限制条件的时候,递归便不再继续。
(2)每次递归调用之后越来越接近这个限制条件。
2.递归练习题
(1)递归输出每一个数
#include<stdio.h>
void print(unsigned int n)
{
if (n > 9) {
print(n / 10);
}
printf("%4d", n % 10);
}
int main(void)
{
unsigned int num;
scanf("%d", &num);
print(num);
return 0;
}
(2)递归输出第n个斐波那契数
#include<stdio.h>
int f(int n) {
int x;
if (n == 0) {
return 0;
}
else if(n<=2){
return 1;
}
else {
return f(n - 1) + f(n - 2);
}
}
int fbnq(int n)
{
int x, i, x3;
int x1 = 0, x2 = 1;
// if (n <= 2) {
// x = x2;
// }
// else
if (n == 0) {
x = 0;
}
else {
for (i = 0; i < n; i++) {
x3 = x1 + x2;
x1 = x2;
x2 = x3;
x = x1;
}
}
return x;
}
int main(int argc, char* argv[])
{
int n;
printf("求第几个斐波那契数:");
scanf_s("%d", &n);
printf("%d\n", f(n));
printf("%d\n", fbnq(n));
return 0;
}
(3)递归求简单交错幂级数的部分和
要求实现一个函数,计算下列简单交错幂级数的部分和: f(x, n) = x?x^2+ x^3?x^4+ ? + (?1)^n-1 x^n
#include<stdio.h>
#include<math.h>//头文字中含有pow函数,
double fn1(double x, int n)//答案
{
if (n == 1)
return x;
else
return x * (1 - fn1(x, n - 1));
//可以多找找函数的特性然后多次利用函数带入求值
}
double fn2(double x, int n)//做
{
int i;
double sum = 0, t;
for (i = 0; i < n; i++)
{
t = pow((-1), i) * pow(x, (i + 1));//pow(x,y)是x的y次方
sum += t;
}
printf("函数中为");
printf("%lf\n", sum);
printf("\n");
return sum;
}
int main(int argc, char* argv[])
{
double x;
int n;
scanf_s("%lf %d", &x, &n);
printf("%.2f\n", fn1(x, n));
printf("\n");
printf("%.2f\n", fn2(x, n));
return 0;
}
(4)递归求字符数组长度
#include<stdio.h>
int mystrlen(char* p)
{
if (*p != 0) {
return 1 + mystrlen(p + 1);
}
else {
return 0;
}
}
int main(void)
{
char m[20];
gets(m);
printf("%d", mystrlen(m));
return 0;
}
(5)递归求阶乘
#include<stdio.h>
int jiecheng(int n) {
int a;
if (n > 1) {
a = n * jiecheng(n - 1);
}
else {
return 1;
}
return a;
}
int main(void)
{
int n,t;
scanf("%d", &n);
printf("\n");
printf("%d的阶乘为", n);
t=jiecheng(n);
printf("%d", t);
return 0;
}
总结:递归的方法属实很巧妙,写出的代码也会更简单有效,但是想一个递归却要很长时间,要更好的使用递归的方法练习这些还远远不够。
3.? ?栈
说到递归就必须提到栈,因为递归的方法很容易导致一个错误叫栈溢出
?
- 栈是一个先进后出的结构,一般用一个桶来描述它,类似于堆盘子,先放到地上的盘子最后被取走(默认只能取走一个盘子)
- 栈其实就是操作受限的线性表,只有一个口,每一次操作时,这个口可以当出口也可以当入口.
?
?栈在我的理解中就相当于一个内存盒子,每次创建函数会给给函数一块内存区域,然后逐渐向上堆积。
在栈区申请一段空间分配给main函数,?在main函数的栈帧空间又给申请的int变量什么的分配空间,而外部函数是从内存的栈区另外开辟的空间。
先来的在下面,后来的在上面,取出也是从上到下取。
递归会在main函数的临近的区域申请栈空间,过多会造成栈溢出。
?
?所以用递归需要注意
(1)写代码时不能死递归,都要有跳出条件,并且应该每次递归逼近跳出条件。
(2)递归层次不宜太深
二.常用字符串函数
1.stpcpy?
功能: 拷贝一个字符串到另一个 ,将串2连同结束符一起从串1的0下表位置开始覆盖
格式:strcpy(串1首地址,串2首地址)
#include<string.h>
#include<stdio.h>
int main(void)
{
char s[20] = "china";
char t[10] = "521";
char k[30];
strcpy(k, s);
strcpy(s, t);
strcpy(t, k);
puts(s);
puts(t);
return 0;
}
2.strcat
功能: 字符串拼接函数 ,将串2连同结束符一起从串1的结束符位置开始向后覆盖
格式:strcat(串1首地址,串2首地址)
3.?strchr?
功能: 在一个串中查找给定字符的第一个匹配之处
格式: strchr(串首地址, 字符);?
4.strcmp?
功能: 串比较 ,前大后为1,前小后为-1,前等后为0,搭配if语句来使用
格式: strcmp(char *str1, char *str2);?
5.strrev
功能:字符串倒置
格式:strrev(数组首地址);
6.strlwr
功能:字符串大写转小写
格式:strlwr(数组首地址);
7.strupr
功能:字符串小写转大写
格式:strupr(数组首地址);
三.指针学习
1.定义指针变量时,“*”是指针定义符,用来说明该变量是指针变量;对指针所指变量进行间接
访问时,“* ”是间接引用运算符,用来访问指针所指存储单元。
? ? 说明:因为指针中只能存放x变量的“首地址”,因此int *p;这个定义,实际上是告诉计算机以“访问
整形数据”的方式“看待”内存。也就是说,先通过p找到x所在内存的开始位置,然后因为p只能访
问整数,所以一次性从内存中取出4个字节进行访问。
指针赋值需要基类型一致,即int的指针不能给double指针赋值
int num;
int *p=#
num=100;
*p=100;
“*”号的用法
(1)首先出现的*p,用来声明p是指针;
(2)当p被定义为指针后,再次出现的*p,表示获得p所指单元的内容。
(3)指针变量存放该指针指向变量的存储地址,内存地址通常是一个无符号整数,因此,所有指
针变量占有相同大小的存储空间,具体占有的存储单元数与计算机系统和编译器有关。
注:在32位的操作系统中,指针变量占有32bit的内存单元;在64位的操作系统中,指针变量占有64bit的内存单元;
int *p;
系统为变量p分配存储空间,由于尚未给指针变量p赋值,则指针变量p是“值无定义的”,可能指
向内存中任何位置,这种指针称为野指针。野指针在程序中很危险,可能导致系统崩溃。(访问到不知道的区域,如果存有重要信息,则容易被黑客黑掉系统)
?2.练习
考核时指针交换数居然不会做,属实不应该,下去自己反省并做了一些指针的题。
(1)指针找数
#include<stdio.h>
#define N 7
int main(void)
{
int num[N] = { 2,5,8,4,3,6,1 };
//gets(num);
int n,index=0;
printf("要查找的数字为");
scanf("%d", &n);
int *p=num;
for (; p < num + N; p++) {
if (*p == n) {
index = p - num;
break;
}
if (p == num + N) {
index = -1;
break;
}
}
puts(num);
if (index == -1) {
printf("查找失败");
}
else {
printf("该数字在第%d个出现", index+1);
//数组从0 开始,是数组中的第n项即为第n+1个
}
return 0;
}
(2)二维数组的倒置
首先是数组的做法,用一个数组接需要倒置的数组
#include<stdio.h>
#define M 3
#define N 4
int main(void) {
int k[M][N];
int i, j;
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
scanf("%d", &k[i][j]);
}
}
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
printf("%4d", k[i][j]);
}
printf("\n");
}
printf("\n");
int l[M][N];
int a, b;
for (i = 0; i < M; i++ )
{
for (j = 0; j < N; j++)
{
l[i][j] = k[M-1-i][N-1-j];
}
}
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
printf("%4d", l[i][j]);
}
printf("\n");
}
return 0;
}
然后是指针的做法
#include<stdio.h>
#define M 3
#define N 4
void inverse(int* p,int n)
{
int* q;//在这里将二维数组看成一维数组处理
q = (p + n-1);//-1在这里要格外注意,因为数组的长度是他下标-1,从0开始的
int t;
while (p < q) {
t = *p;
*p = *q;
*q = t;
p++;
q--;
}
}
int main(void)
{
int k[M][N];
int i, j;
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
scanf("%d", &k[i][j]);
}
}
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
printf("%4d", k[i][j]);
}
printf("\n");
}
inverse(&k[0][0],12);
printf("\n");
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
printf("%4d", k[i][j]);
}
printf("\n");
}
return 0;
}
这段代码中将二维数组看成一维数组传入函数中进行处理,双指针的方法,p指针前移q指针后移实现倒置。
注:二维数组看成一维数组是一种常用的处理二维数组的方法,如下图
形式 | 性质 | 含义 | a | 行指针 | 二维数组名,指向一维数组a[0],相当于&a[0][0] | a+i | 行指针 | 指向一维数组a[i],相当于&a[i][0] | *a | 列指针 | 即*(a+0),指向第0行第0列,相当于&a[0][0] | *(a+i) | 列指针 | 指向第i行第0列,相当于&a[i][0],相当于a[i] | *(a+i)+j | 元素指针 | 指向第i行第j列,相当于&a[i][j],相当于a[i]+j |
3.
#include<stdio.h>
int *sum(int x,int y)
void main(){
int *r=sum(10,9);
printf("10+9=%d",*r);
}
int *sum(int x,int y){
int s;
s=x+y;
return &s;
}
上述代码巧妙的从函数中返回了一个指向数的指针,然后取值就可加和。
4.
(1).*p =1,此操作为赋值操作,即将指针指向的存储空间赋值为1。此时p指向数组nums的第一个元素,则此操作将nums第一个元素赋值为0,即nums[0] =1。
(2).p + 1,此操作为指针加整数操作,即向前移动一个单元。此时p +1指向nums[0]的下一个元素,即nums[1]。通过p+整数可以移动到想要操作的元素(此整数可以为负数)。
(3).如上面, p (p +0)指向nums[0]、p +1指向nums[1]......类推可得,p+i指向nums[i],由此可以准确操作指定位置的元素。
(4).在p+整数的操作要考虑边界的问题,如一个数组长度为2,p+3的意义对于数组操作来说没有意义。
5.指针问题
计算成绩的平均数
#include<stdio.h>
#include<stdlib.h>
void average001(int *p, int n)
{
float sum = 0;
int *x;
x = p;
float aver;
for (; p < (x+n); p++) {
printf("%4d", *p);
sum += (*p);
}
printf("\n");
aver = sum / n;
printf("总平均成绩为");
printf("%5.1lf\n", aver);
printf("\n");
}
void average002(int* p, int n)
{
float sum = 0;
int i = 1, t;
float aver;
int* x;
x = p;
for (; p < (x + n); p++) {
sum += (*p);
if (p != x) {
t = (p - x);
}
if (t % 4 == 0) {
printf("第%d个同学总成绩为", i++);
printf("%.1d\n", sum);
aver = sum / n;
printf("平均成绩为%.1f\n", aver);
printf("\n");
sum = 0;
}
if (i == 4) {
break;
}
}
}
void search001(int n,int (*p)[3])
{
int i;
printf("第%d个同学各科成绩分别为", n+1);
for (i = 0; i < 4; i++) {
printf("%4d", *(*(p+n)+i));//可以换为score[n][i],p[n][i]
}
}
int main(void)
{
int score[3][4];
int i, j,n;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
scanf("%d", &score[i][j]);
}
}
int* p;
p = score;
scanf("%d", &n);
average001(&score[0][0],12);
average002(&score[0][0], 4);
search001(n,score);
return 0;
}
现在这段代码可以计算所有的成绩的平均值,但是average2中我想计算每个人的平均成绩出问题了,指针还是运用的不是那么熟练,还得继续学习。
以上便是本周的学习内容了。
|