学习C语言第九天

欢迎使用C语言

C递归

递归指的是在函数的定义中使用函数本身的方法。
流程图
C语言支持递归,即一个函数可以调用其本身。但在使用递归时,需要注意定义一个从函数退出的条件,否则会进入死循环。递归函数在解决许多数学问题上都其了至关重要的作用。

递归与直接的语句(while循环)相比,递归函数会耗费更多的运行时间,并且要占用大量的栈空间。递归函数每次调用自身时,都需要把它的状态存到栈中,以便在它调用自身后,程序可以返回到它原来的状态。

采用递归方法的前提:

1.可以把要解决的问题转化为一个新问题,而这个新的问题的解决方法扔与原理的解决方法相同,只是所处理的对象有规律地递增或递减。
说明:解决问题的方法相同,调用函数的参数书每次不同(有规律地递增或递减),如果没有规律也就不能使用递归调用。
2.可以应用这个转化过程使问题得到解决。
说明:使用其他的办法比较麻烦或很难解决,而使用递归的方法可以很好地解决问题。
3.必定要有一个明确的结束递归的条件。
说明:一定要能够在适当的地方结束递归调用。不然可能导致系统崩溃。

C可变参数

C语言允许定义一个函数,能根据具体地需求接受可变数量的参数。
函数a()最后一个参数写成省略号,即三个点号(…),省略号之前的那个参数是int,代表了要传递的可变参数的总数,为了使用这个功能,需要使用stdarg.h头文件,该文件提供了实现可变参数功能的函数和宏。具体步骤如下:
1.定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
2.在函数定义中创建一个va_list类型变量,该类型是在stdarg.h头文件中定义的。
3.使用int参数和va_start宏来初始化va_list变量为一个参数列表。宏va_start是在stdarg.h头文件中定义的。
4.使用va_arg宏和va_list变量来访问参数列表中的每个项。
5.使用宏va_end来清理赋予va_list变量的内存。

#include<stdio.h>
#include<stdarg.h>
double average(int num,...)
{
    
    
va_list valist;
double sum=0.0;
int i;
//为num个参数初始化valist
va_start(valist,num);
//访问所有赋给valist的参数
for(i=0;i<num;i++){
    
    
sum+=va_arg(valist,int);
}
//清理为valist保留的内存
va_end(valist);
return sum/num;
}
void main(){
    
    
printf("Average of 2,3,4,5=%f\n",average(4,2,3,4,5));
printf("Average of 5,10,15=%f\n",average(3,5,10,15));
}

va_list:用来保存宏va-start、va_arg和va_end所需信息的一种类型。为了访问变长参数列表中的参数,必须声明va_list类型的一个对象,定义:typedef char *va_list;
va_start:访问变长参数列表中的参数之前使用的宏,它初始化用va_list声明的对象,初始化结果供宏va_arg和va_end使用;
va_arg:展开成一个表达式的宏,该表达式具有变长参数列表中下一个参数的值和类型。每次调用va_arg都会修改用va_list声明的对象,从而使该对象指向参数列表中的下一个参数;
va-end:该宏使程序能够从变长参数列表用宏va_start引用的函数中正常返回。
va在这里是variable-argument(可变参数)的意思。

C内存管理

序号 函数和描述
1 void *calloc(int num,int size);

在内存中动态地分配num个长度为size的连续空间,并将每一个字节都初始化为0。所以他的结果是分配了num*size个字节长度的内存空间,并且每个字节的值都是0。

2 void free(void *address);

该函数释放address所指向的内存块,释放的是动态分配的内存空间。

3 void *malloc(int num);

在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不被初始化,它们的值是未知的。

4 void *realloc(void *address,int newsize);

该函数重新分配内存,把内存扩展到newsize。

上述的函数都可以在

动态分配内存

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main(){
    
    
char name[100];
char *description;
strcpy(name,"Zara Ali");
//description=(char *)malloc(200 *sizeof(char));
description=calloc(200,sizeof(char));
if(description==NULL){
    
    
fprintf(stderr,"Error-unable to allocate required memory\n");
}else{
    
    
strcpy(description,"Zara ali a DPS student in class 10th");
}
printf("Name=%s\n",name);
printf("Description:%s\n",description);

}

重新调整内存的大小和释放内存

当程序退出时,操作系统会自动释放所有分配给程序的内存。建议在不需要内存时,都应该调用函数free()来释放内存。或者通过调用函数realloc()来增加或减少已分配的内存块的大小。

void的作用

对函数返回的限定,对函数参数的限定。
一般常见的就是这两种情况:
当函数不需要返回值值时,必须使用void限定,这就是我们所说的第一种情况。void func(int a,char *b)。
当函数不允许接受参数时,必须使用void限定,这就是我们所说的第二种情况。int func(void).

void指针的使用规则

1.void指针可以指向任意类型的数据,就是说可以用任意类型的指针对void指针赋值。如果要将void指针p赋给其他指针,则需要强制类型转换,如a=(int *)p。在内存的分配中可以见到void指针使用:内存分配函数malloc函数返回的指针就是void * 型,用户在使用这个指针时,要进行强制类型转换,就是显式说明该指针指向的内存中是存放的什么类型的数据。(int *)malloc(1024)表示强制规定malloc返回的void *指针指向的内存中存放的是一个个的int型数据。
2.如果指针p1和p2的类型相同,可以直接在p1和p2间互相赋值,如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。

float *p1;
int *p2;
p1=(float *)p2;

而void *则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换。

void *p1;
int *p2;
p1=p2;

但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。因为"无类型"可以包容"有类型",而“有类型”则不能包容“无类型”。
小心使用void指针类型:按照ANSI标准,不能对void指针进行算法操作。
void指针可以任意类型的数据,函数可以接受任意类型的指针。任何类型的指针都可以传入memcpy和memset中。void的出现只是为了一种抽象的需要。

C命令行参数

执行程序时,可以从命令行传值给C程序。这些值被称为命令行参数。它们对程序很重要,特别是当人想从外部控制程序,而不是在代码内对这些值进行硬编码时,尤为重要。
命令行参数是使用main()函数参数来处理的,其中,argc是传入参数的个数,argv[]是一个指针数组,指向传递给程序的每个参数。
argv[0]存储程序的名称,argv[1]是一个指向第一个命令行参数的指针,*argv[n]是最后一个参数。如果没有提供任何参数,argc将为1,否则,如果传递了一个参数,argc将被设置为2。
多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数时应把参数放置在双引号""或单引号“内部。
Demo

#include<stdio.h>
void main(int argc,char *argv[]){
    
    
printf("Program name %s\n",argv[0]);
if(argc==2){
    
    
	printf("The argument supplied is %s\n",argv[1]);
	}
else if(argc>2){
    
    
	printf("Too many arguments supplied.\n");
	}
else{
    
    
	printf("One argument expected.\n");
	}
}

分享暂时告别一段时间。

猜你喜欢

转载自blog.csdn.net/qq_31932681/article/details/95366774