指针函数
指针函数以及用法
函数,函数的特征点就是返回值为指针(或者说地址量)。
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.主调函数中有效内存
复习:
应用:编写一个指针函数,实现字符串拷贝功能。
#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;
}