递归
C语言的特点之一就是允许函数的递归调用。
递归前进段,使问题不断缩小。
但栈的空间有限,递归消耗内存大
(1)递归法求斐波那契,引用递归最失败的例子,可能会导致栈溢出
int Fabonacci(int n)
{
int f1=1;
int f2=2;
int f3=1;
if(n==0||n==1)
{
return 1;
}
return Fabonacci(n-1)+Fabonacci(n-2);//1.递归
//2.循环法
//for(int i=2;i<n;i++)
//{
// f3=f1+f2;
// f1=f2;
// f2=f3;
//}
//return f3;
}
int main()
{
printf("%d ",Fabonacci(4));
return 0;
}
(2)汉诺塔问题
int count=0;//全局变量
void Move(char x,char y)
{
printf("%c->%c\n",x,y);
count++;
}
void Hanio(int n,char a,char b,char c)
{
if(n==1)
{
Move(a,c);
}
else
{
Hanio(n-1,a,c,b);//把n-1个盘子从a通过c全部挪到b上
Move(a,c);//把a上最后一个盘子挪到c上
Hanio(n-1,b,a,c);//***
}
}
int main()
{
Hanio(5,'A','B','C');
printf("%d\n",count);//输出移动的次数
return 0;
}
尾递归转为非递归,如上面斐波那契数列中递归法转为循环法
内存的动态分配
1.malloc
原型:void * malloc(unsigned int size);
注:形参size的类型定为无符号整型(不允许为负数),此函数返回的指针指向该分配域的开头位置。
若内存空间不足,则返回空指针NULL
例:int * arr=(int *)malloc(n * sizeof(int));
2.calloc
原型:void * calloc(unsigned n,unsigned size);
用calloc函数可以为一维数组开辟动态存储空间,n为数组元素的个数,size为每个元素的长度。
注:n与size的位置可互换,并且每一个元素自动初始化为0.
例:int * p=(int *)calloc(10,sizeof(int));
3.free
原型:void free(void *p);
作用是释放指针变量p所指向的动态空间,使这部分空间能被其他变量使用。p应该是最近一次调用calloc或malloc函数时得到的返回值。
注:如果没有释放内存,则会发生内存泄露,释放内存时会找首位置所包含的信息,来确定所要释放内存空间的大小。
例:free(p);
(1)内存泄露被回收的三种情况:程序退出、重启、关机,此时所有内存都会被回收。
(2)free的崩溃问题:
a.数组越界(篡改尾数据)
如:
void Fun(int *arr)
{
int * arr=(int *) malloc(10*sizeof(int));
for(int i=0;i<=10;i++)
{
arr[i]=0;
printf("%d ",arr[i]);
}
//free(arr);
}
如果没有free,只是单纯的打印arr的值,C语言不会检查自己是否越界。因为越界的地址暂时没有用到,如果越界的地址被已内存占用,而再使用的话,程序就会崩溃。
加上free之后,运行程序程序会崩溃。
b.移动了指针
如:
int * p=(int * )malloc(10*sizeof(int));
......
p++;
malloc函数的返回值才可以用来释放内存,p移动之后p的值已经不是申请的地址的返回值了,所以free会崩溃
c.重复释放内存
free(p); //1.
free(p); //2.此时的p是野指针
free 释放函数时,实际是malloc给指针一个合法的地址,并且该地址指向一个合法的内存空间。free之后,这部分内存空间可以重新被其他变量使用,但free后的指针仍然存在,其值还是刚刚分配的内存空间的地址,并不是0(NULL).因此上面free 1.并不能使p置NULL,而需要手动设置p=NULL
4.realloc
原型:void * realloc(void * p,unsigned int size);
可以同realloc改变内存空间的大小,进行重新分配。【一般对内存紧缩,即改小内存没有用】
例:p=(int * )realloc(p,20*sizeof(int));
等价于:
int * q=(int * )malloc(20*sizeof(int));//申请20个内存单元
for(int i=0;i<10;i++)
{
q[i]=p[i];//把p的内容搬到q
}
free(p);//释放10单元内存的变量p
p=q;//更新q的地址依旧为p
p=NULL;//使p为空(NULL)
free(q);//即free(NULL);
判断一个字符是否是字母,数字,不用字符函数和字符串函数,不用字符集
1.判断一个字符是否是16进制数
#include<stdio.h>
#include<string.h>
bool Myisxdigit(char ch);
{
char chars[]="0123456789abcdefABCDEF";
for(int i=0;i<strlen(chars);i++)
{
if(ch == chars[i])
{
return true;
}
}
return false;
}
int main()
{
if(Myisxdigit(r))
{
printf("true");
}
else
{
printf("false");
}
return 0;
}
2.判断一个字符是否是字母
bool Myisalpha(char ch);
{
char chars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for(int i=0;i<strlen(chars))
{
if(ch == char[i])
{
return true;
}
}
return false;
}