函数与指针

在C语言中,不仅是变量,数组,有地址,其实我们的函数也有地址
有地址的东西,我们就可以用一个指针变量来保存它们的地址,并且
可以通过该指针去访问指向的对象
函数也有地址--->函数指针

11.函数指针  
函数指针是一个指针,只不过该指针指向的是一个函数。

1)函数指针如何定义呢
	指向的类型 *指针的变量名;
	
	int sum(int,int);
	int sum(int a,int b)
	{
	}
	要定义一个指针变量p,来保存函数sum的地址,怎么定义呢?
	指向的类型 *p;
	typeof(sum) *p;
	
	如何来描述一个函数的类型的?
		函数的类型 三要素:
		函数的返回值 函数名(函数的参数类型列表)
		int (int,int)==>就是描述一个类似sum函数的
			返回值类型 (形参的类型列表)
	
	如:
		int *abc(int a,float b)
		{
		}
		描述abc的类型:
		int *(int,float)
			->是一个返回int*类型名,带一个int,一个float的函数
			类型。
		
		int sum(int a,int b)
		{
		}
		描述sum的类型
		int (int,int)
		typeof(sum) *p;
		==>
			int (int,int) *p;
			int (*p)(int,int);
			
		函数指针的定义方法:
			指向函数的返回值类型 (*指针变量名) (指向函数的形式参数类型列表);
			
		练习:
		1.请定义一个指针变量p,来保存函数abc的地址
		int *abc(int a,int *b)
		{
		}
		
		int* (*p)(int,int *);
		2.请定义一个指针变量p,来保存如下函数的地址
		int sum_array(int *a,int n)
		
		//int a[10];int *p=a;
		//*(p+i) <==> p[i] 
		int sum_array(int a[],int n)
		{
		}
		int (*p)(int *,int);
		数组名作为函数的参数(形参,实参),当作一个指针来用的。
		
	2)怎么给函数指针赋值呢?
		p=函数的地址
		函数的地址怎么获取呢?
			&对象名 => 取对象的地址 
		&函数名
		函数名:在C语言中,函数名本身就代表函数的首地址《-------------
		
		练习:
		int sum_array(int *a,int n)
		{
		}
		//定义一个函数指针p 指向sum_array 
		int (*p)(int *,int)=&sum_array;
		int (*p)(int *,int)=sum_array;			
		<==>
		int (*p)(int *,int);
		p=&sum_array;
		int (*p)(int *,int);
		p=sum_array;;
		<==>
		int *p=&a;
		int *p;
		p=&a;
		p指向函数sum_array
		
	3)怎么通过函数指针去调用指向的函数呢?
		p=&sum_array
		*p=>*&sum_array==>sum_array
		
		
		p=sum_array
		p=>sum_array
		
		通过函数指针去调用指向的函数。有如下两种方式:
		p为函数指针名
		1)(*p)(实参列表)
		2)p(实参列表)
		
	练习:
		1.在main中定义了一个函数指针p,通过p去调用sum_array
		求数组元素的和-->sum_array
		==>一维数组
		int sum_array(int a[],int n);
		int sum_array(int *a,int n)//int a[10]; a typeof(a) typeof(&a[0)) 
		=>tyepof(a[0]) *=>int* 
		{
			int i;
			int sum =0;
			for(i=0;i<n;i++)
			{
				sum+=a[i];//*(a+i) <==> a[i]
			}
			return sum;
		}
		main()
		{
			int a[10]={.....};
			int (*p)(int* ,int)=sum_array;
			int sum=p(a,10);
			//int (*p)(int* ,int)=&sum_array; 
			//int sum=(*p)(a,10);
		}
		
		2.在main中定义了一个函数指针p,通过p去调用xxx_num
		==>二维数组
		int xxx_num(int (*a)[4],int n);
		int xxx_num(int a[][4],int n)
		{
			printf("恭喜你调用成功!\n");
			return 0;
		}
		
		int (*p)(int (*)[4],int);
		----------------------------------------------------
		int a[3][4]; => int[4] a[3];
							a[0] //一维数组 a[0]是这个一维数组的名字
							//是一个含有4个int类型元素的一维数组
							a[1]
							a[2]
						int[4] a[]
		
		数组当作函数的参数的时候,形参一般这样子设计:
			数组元素的类型 数组名[],元素的个数
			int a[][4],int n   (1)
		数组名当函数参数,当指针来看:
			a=>&a[0]
			typeof(a)==>typeof(&a[0])==>typeof(a[0]) *
			=>int[4] *
			
			数组元素的类型 *指针变量名,元素的个数 (2)
			int (*a)[4], int n(2)
	
	---------------------------------------------------------------------
	12.二级指针与多级指针
		int a;
		可以定义一个指针变量p来保存a的地址
			typeof(a) *p;//指向类型 *指针变量;
			int *p;
			p=&a;//p->a
				*p=>*&a==>a 
				
			p本身也有地址,我们可以定义一个指针变量p2来保存p的地址
			typeof(p) * p2;
			int ** p2;
			//p2二级指针,它保存的是一个一级指针的地址
			//有人说,我要分清到底是两级指针还是一级指针,怎么区分呢?
			//QNMLB,你只要知道它是一个指针(并且它保存了谁的地址)就可以了

			p2=&p;
			*p2 =>*&p=>p 
			**p2 ==> **&p =>*p=>a 
			
			a=1024;
			*p=1024;
			**p2=1024;
		------------------------
		main()
		{
			int n;
			scanf("%d",&n);
			int a[n];//动态数组,根据用户输入,数组元素的个数动态改变的。
		}
		“如何来实现动态数组的分配呢?”
		
	13.动态内存分配函数
		malloc/realloc/calloc
		free
		NAME
			malloc, free, calloc, realloc - allocate and free dynamic memory

	       #include <stdlib.h>

		   void *malloc(size_t size);
		   malloc: memory allocate 内存分配
			
			malloc用来动态分配一个size大小的内存空间,并且把分配到内存空间
			的首地址返回。malloc分配的空间的生存期,是随进程持续性。
			malloc分配的空间一旦分配给你,它不会自动释放,一定要手动调用
			free或这个进程消亡了。
				size:要分配的空间的大小(以字节为单位)
				返回值:
					成功返回分配到的空间的首地址,
					失败返回NULL;
			例子:
				int a[n];
				==>
				int *p=(int*)malloc(n*sizeof(int))
				p[0]
				p[1]
				..
				*(p+i)
			malloc可能会导致内存泄漏(产生一些垃圾内存)
				int *p=malloc(100);//p指向一个100字节的内存空间
					//通过p指针操作访问这段空间
				p=&a;//p指向a,那100字节的空间,就没有指向指向了它
				...
				这100个字节的空间,是不是访问不了啦,但是这段空间
				又不能分配给别人,这样的内存,我们称之为“垃圾内存”
				把这种现象称之为“内存泄漏”
				
				java 垃圾回收机制!!!
				void free(void *ptr);
				free 用来释放ptr所指向的内存的
					ptr必须是malloc/calloc/realloc这是三个函数申请的内存
		------------------------------------------------------------------			
		   void *calloc(size_t nmemb, size_t size);
			作用类型malloc,不过它是数组分配函数,
			它分配一个数组空间,它带两个参数
				n表示分配多少个元素
				size表示每个元素占多少字节
				so.它共分配的连续空间的大小:size*n 
				
				并且calloc分配空间,它把空间的内容全部置0、
			
				=>malloc(n*size)
					清0
		------------------------------------------------------------------			
		   void *realloc(void *ptr, size_t size);
			re:repeat 重复
			realloc用来把ptr(由malloc/calloc/realloc返回动态内存的地址)
			指向的动态内存,扩展到size大小
			ptr == NULL
				realloc(NULL,size)<==>malloc(size);
			ptr != NULL
				扩展
				1.size>原来的大小
				realloc用来把ptr指向的内存,扩展到size字节,原来的前面的内存
				内容保持不变,后面的新增的内存内容不会初始化
					a.原址扩建
					b.整体搬迁
				
				2.size == 0
					realloc(ptr,0)<==>free(ptr)
					
				3.size<原来的大小
					这种情况,作者自己都没有考虑到这种行为。
					结果未定义的(undefined ,什么结果都有可能发生);
		
		14.数组作为函数参数的问题
			把数组当作函数参数:
				(1)数组元素类型 数组名[],元素的个数 
				(2)数组元素类型 *指针变量名,元素的个数
			1)
				int a[10]
				func(int p[],int n);
				func(int*p,int n);
			2)
				int a[3][4];
					int[4] p[],int n==> int p[][4],int n 
					int[4]* p,int n==>int (*p)[4],int n 
					
		15.main的参数问题
			在linux下面,程序运行的时候,可以带参数,只不过所有的参数都当作是字符串
			来处理。
			如:
				./main 123 456 "abc efg"
				参数多个字符串==>字符串的数组
			
			char *argv[]={"./main","123","456","abc efg"};
			
			在运行main函数的时候,可以把上面那个数组传递给main函数,
			so,linux下面的C程序的main的参数可以如下定义:
				元素个数,数字元素类型  数组名[]
				or
				元素个数,数组元素类型 *指针变量名 //char * *argv
			int main(int argc,char *argv[])
			or
			int main(int argc,char** argv)
			{
			}
		练习:
			请使用主函数的参数计算两个数的和 积
			./main  456 + 789
			=>
			./main 456 * 789
			=>
			
	总结:
		1.指向
			如果p保存了a的地址,那么我们就说p指向a
			p指向的类型就是a的类型 
			
			指针变量的定义
				指向的类型 * 指针变量名;
			
			&x:指针,因为保存了x的地址
				typeof(&x)=> typeof(x) *
				
		2.&地址 <==>地址对应的那个对象(变量,函数)
			*&a <==> a 
		
		3.
			*(a+i) <==> a[i],when i>=0 
			例子:
				p[3][4]<==>*(p[3]+4]<==>*(*(p+3)+4)
				
		4.指针作加减的问题
			p+i(p是一个指针,i是一个整数)
				不是简单的加减数值,而是加减i个指向单元的长度
		
		5.数组名的问题 
			数组名可以看作是指向第一个元素类型的常量指针
			数组名在数值上为第一个元素的地址
			数组名a,在代码中有两个意思
				1)代表整个数组
					typeof(a)
					siezof(a)
					&a 
				2)在合适的情况下,可以当作指针看
					&a[0]
					
		6.指针数组与数组指针
			主函数的参数的那个数组 是指针数组
			
		7.字符串API函数 
			strlen
			strcpy strncpy
			strcmp/strncmp
			strcat/strncat
		
		8.函数指针
		
		9.动态内存 
			malloc/realloc/calloc/free 
			
	作业:
	0.前面的那套试卷 数组和函数  
		输入 ./a.out 3 + 5 ,输出 8 。(3位数以上 8位数以下的数)(7/2 = 3.5)输出字符串



	  1 . 字符串的大小写转换:请编写一个函数,实现讲字符串的大小写转换功能,数字不变。
		
		例:输入 AD5ChadCtT  输出 ad5cHADcTt


	  2.  字符串的倒序 : 请编写一个函数,实现字符串的倒序输出。
		
		例:输入 woshishazi520  输出 025izahsihsow

	  3.	删除字符串中的子串 :请编写一个函数,实现下面的功能:
		
		 输入2个字符串S1和S2,要求删除字符串S1中出现的所有子串S2,即结果字符串中不能包含S2。
		
		例 输入:
			Tomcat is a male ccatat
			cat
		   输出:
		
			Tom is a male
	 
	  4.  字符串的循环左移:请编写一个函数,实现下面的要求:
			
			输入:输入在第1行中给出一个不超过100个字符长度的、以回车结束的非空字符串;第2行给出非负整数N。
			例: Hello World!
				 3
			
			输出:在一行中输出循环左移N次后的字符串。
			例 :lo World!Hel

	  5. 字符串的最长对称子串。请编写一个函数,得到一个字符串的最长对称子串及其长度:(考虑奇数和偶数的情况)
		
		例 输入:  nihaoaoahhaoin
			
		   输出:  haoaoah 7

	  6.经典混合题

		#include<stdio.h>
		#include<windows.h>
		int main()
		{
			char *c[] = { "ENIER","NEW","POINT","FIRST" };
			char **cp[] = { c + 3,c + 2,c + 1,c };
			char ***cpp = cp;
			printf("%s\n", **++cpp);
			printf("%s\n", *--*++cpp + 3);
			printf("%s\n", *cpp[-2] + 3);
			system("pause");//暂停 等待
			return 0;
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值