Day 12 - 13 :指针函数、函数指针以及qsort函数

指针函数

指针函数以及用法

        函数,函数的特征点就是返回值为指针(或者说地址量)

        int * fun (int x , int y) ;

        语法:<数据类型> * <函数名称> (<参数说明>) {

        语句序列;

        }

        应用:打印一份字符数组和字符串。

            “ 1、 局部变量存储在栈中。

              中的变量内存会随着定义所在区间的结束自动释放
              2、 全局变量、静态变量(全局和局部静态变量)以及字符串存储在静态存储区

              对于静态存储区,其中的变量常量在程序运行期间会一直存在,不会释放,且变量常量在其中只有一份拷贝,不会出现相同的变量和常量的不同拷贝。” 来源:各种变量、字符串(存储位置和生命周期)

#include<stdio.h>
const char* mystring()
{
	const char* s = "hello";
	return s;
}
char* get_char_array()
{
	char ch[10] = { 'a','b','c' };
	return ch;
}
int main()
{
	char* s;
	s = get_char_array();
	printf("%s\n", s);
	//s不能指向ch数组,因为字符数组是局部变量,即只在函数内有效。
	const char* p;
	p = mystring();
	printf("%s \n", p);
	//p能指向s字符串:该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。
	return 0;
}

        strcpy函数:将源头指向的C字符串复制到目标指向的数组中,包括结尾的'/0'字符,并在'\0'字符处停止拷贝。(注意:要加头文件# include <string.h>)

        语法:char * strcpy ( char * destination, const char * source );

        例:把s2的字符串拷贝给s1。

#include<stdio.h>
#include<string.h>
int main()
{
	char s1[100];
	char* s2 = "welcome";
	strcpy(s1, s2);
	printf("%s\n", s1);
	return 0;
}

指针函数的返回值

        问题引入:以下程序有什么问题?

#include<stdio.h>
const char* mystring()
{
	char str[20];
	strcpy(str, "hello");
	return str;
}
int main()
{
	printf("%s\n", mystring());
	return 0;
}

       答:由上文可知局部变量和字符串生命周期的问题,str字符数组作为局部变量,存储在栈内,一旦函数返回,数组被销毁。

        解决方法:

        1.改为全局变量

#include<stdio.h>
#include<string.h>
//1.全局变量
char str[20];
char* mystring()
{
	//char str[20];
	strcpy(str, "hello");
	return str;
}
int main()
{
	printf("%s\n", mystring());
	return 0;
}

        2.改成字符串常量

        3.static变量的地址(还没学过)

        4.堆的地址

        5.主调函数中有效内存

        复习:

        Day 2:字符数组和字符串-CSDN博客

        Day 7: 字符指针与字符串-CSDN博客

        应用:编写一个指针函数,实现字符串拷贝功能。

#include<stdio.h>
char* strcpy_a(char* q, const char* p);
int main()
{
	char s1[] = "hello world!";
	// error:char * s1 ="hello world!"
	// 因为本程序涉及修改字符串字面量是未定义行为,应使用字符数组避免。
	char s2[50] = "ABC";
	printf("%s\n", strcpy_a(s2, s1));
	return 0;
}
char* strcpy_a(char* q, const char* p)
{
	char* start = q;
	while (*p != '\0')
	{
		*q = *p;
		q++;//error:*q++ (复习)
		p++;
	}
    //以上{}内可以改成:*q++ = *p++;
	*q = '\0';
	return start;//返回目标字符串的起始地址。
}

        应用:编写字符串连接函数。

#include<stdio.h>
char* my_strcat(char* q, const char* p);
int main()
{
	char ch1[50] = "abc" ;
	char ch2[] = "defg" ;
	printf("%s\n", my_strcat(ch1, ch2));
	printf("%s\n", ch1);
	return 0;
}
char* my_strcat(char* q, const char* p)
{
	char* start = q;
	while(*q != '\0')
	{
		q++;
	}
	while(*p != '\0')
	{
		*q++ = *p++;
	}
	*q = '\0';  
	return start;
}

        应用:编写一个指针函数,把整数123转化为字符串“123”。

#include<stdio.h>
char* my_itoa(int num, char* s);
int main()
{
	int a = 123;
	char s[100];
	printf("%s\n", my_itoa(a, s));
	return 0;
}
char* my_itoa(int num, char* s)
{
	char* start = s;
	int i = 0;
	int j = 0;
	char t= 0;
	while (num != 0)
	{
		s[i] = num % 10 + 48;//ASCII码表中整数0和字符0差48
		i++;
		num  = num / 10;
	}
	s[i] = '\0';
	i--;
	while (j < i)
	{
		t = s[i];
		s[i] = s[j];
		s[j] = t;
		j++;
		i--;
	}
	return start;
}

递归函数

        定义:一个函数的函数体中直接或间接调用了该函数自身,递归函数一定要有结束条件

        问题引入:编写一个递归函数,计算n!。

#include<stdio.h>
int my_acn(int n);
int main()
{
	int n = 0;
	int ret = 0;
	printf("请输入阶乘:\n");
	scanf_s("%d", &n);
	ret = my_acn(n);
	printf("%d",ret);
	return 0;
}
int my_acn(int n)
{
	if (n == 1)
	{
		return 1;//递归的出口
	}
	return (n * my_acn(n - 1));
    //1.递推阶段:
    //5 * F(4)
    //    4 * F(3)
    //        3 * F (2)
    //            2 * F(1)
    //终止条件:       1
    //2.回归阶段:
    //             return 1;
    //        return(2*1);
    // ...
}

        递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件。

        回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解。

        应用: 编写一个递归函数,计算斐波那契数列其数值为:1、1、2、3、5、8、13、21、34……在数学上,这一数列以如下递推的方法定义:F(0)=1,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2)

#include<stdio.h>
int fab(int n);
int main()
{
	int num = 0;
	int ret = 0;
	printf("请输入:");
	scanf_s("%d", &num);
	ret = fab(num);
	printf("%d", ret);
	return 0;
}
int fab(int n)
{
	if (n == 1 || n == 0)
	{
		return 1;
	}
	return (fab(n - 1) + fab(n - 2));
}
//1.递推阶段
//F(4)	+	F(3)
//F(3)+F(2)	+ F(2)+F(1)
//F(2)+ F(1) + F(1)+ F(0) + F(1)+ F(0) + F(1)
//F(1)+F(0)+ F(1) + F(1)+ F(0) + F(1)+ F(0) + F(1)

函数指针

基本用法

        概念:函数指针用来存放函数的地址,这个地址是一个函数的入口地址。

        函数名代表了函数的入口地址。

        语法:<数据类型>(*<函数指针名称>)(<参数说明列表>);

        <数据类型> :函数指针所指向的函数的返回值类型

        <参数说明列表>:应该与函数指针所指向的函数的形参说明保持一致

     (*<函数指针名称>):*说明为指针()不可缺省,表明为函数的指针。

        举例:

#include<stdio.h>
void print_hello();
void print_hello2(int a);
int main()
{
	//1.打印 hello world!
	print_hello();
	printf("%p\n", print_hello);
	//2.打印 helloworld! + 整数
	int a = 100;
	void (*p)(int);	    //声明
	p = print_hello2;   //赋值
	                    //调用
	p(100);
	(*p)(100);

	return 0;
}
void print_hello()
{
	printf("hello world!\n");
}
void print_hello2(int a)
{
	printf("hello world! %d\n",a);
}
#include<stdio.h>
int add(int a, int b);
int sub(int a, int b);
int main()
{
	int a = 10;
	int b = 6;
	int (*p)(int, int);
	p = add;
	printf("%d\n",p(a, b));
	p = sub;
	printf("%d\n", p(a, b));
	return 0;
}
int add(int a, int b)
{
	return (a + b);
}
int sub(int a, int b)
{
	return (a - b);
}

函数指针数组

        语法:<数据类型> (*<函数指针数组名称> [<大小>] ) (<参数说明列表>);

        <大小>是指函数指针数组元素的个数

#include<stdio.h>
int add(int a, int b);
int sub(int a, int b);
int main()
{
	int a = 10;
	int b = 6;
	int (*p[2])(int, int);
	p[0] = add;
	p[1] = sub;
	printf("%d\n", p[0](a,b));
	printf("%d\n", p[1](a, b));
	return 0;
}
int add(int a, int b)
{
	return (a + b);
}
int sub(int a, int b)
{
	return (a - b);
}

qsort函数

        应用:调用C库中的qsort函数来实现整形数组的排序。

#include<stdio.h>
#include<stdlib.h>//注意头文件
int compare(const void* p1, const void* p2);//比较函数
int main()
{
	int a[] = { 56,23,1,6,9,25 };
	int n = sizeof(a) / sizeof(int);
	int i;
	qsort(a, n, sizeof(int), compare);//(数组的起始地址,元素个数,一个元素的大小,比较函数)
	for (i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}
int compare(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值