27.常量和指针
代码 | ``` |
---|
- 指针可以修改为指向不同的常量
- 指针也可以修改为指向不同的变量
常量指针
常量指针
指针本身不能改变 但是指向的值是可以改变的
#include <stdio.h>
int main()
{
int num = 520;
const int cnum = 880;
int * const p = #
*p = 1024;
printf("*p:%d\n",*p);
// p = &cnum; //不可以被修改
//printf("*p:%d\n",*p);
return 0;
}
28.函数
定义函数和函数调用
打印函数的封装
#include <stdio.h>
//常见的打印图案函数调用
void print_C();
void print_C()
{
printf(" ###### \n");
printf("## ## \n");
printf("## \n");
printf("## \n");
printf("## ## \n");
printf(" ###### \n");
}
int main()
{
print_C();
return 0;
}
函数的定义
类型名 函数名(参数列表)
{
函数体
}
函数的声明
- 声明就是告诉编译器我们要使用这个函数
- 声明(Declaration)
函数的参数和返回值
示例1:编写一个函数sum,由用户输入参数n,计算1+2+3+……….+(n-1)+n的结果并返回。
#include <stdio.h>
int sum(int n);
int sum(int n)//n为形参
{
int result = 0;
do {
result += n;
}while(n-- > 0);
return result;
}
int main()
{
int n,result;
printf("请输入n的值:");
scanf("%d",&n);
result = sum(n);
printf("1+2+3+..........+(n-1)+n的结果是:%d\n",result);
}
示例2:编写一个函数Max,接收两个整型参数,并返回他们中较大的那个
#include <stdio.h>
int max(int,int);
int max(int x,int y)
{
if(x>y)
return x;
else
return y;
}
int main()
{
int j,k;
printf("请输入两个整数:");
scanf("%d",&j);//scanf("%d%d",&j,&k);
scanf("%d",&k);
printf("较大的值为%d",max(j,k) );
}
29.参数和指针
形参和实参
- 当函数发生调用时 实参的值会传递给形参
传值和传址
传值
#include <stdio.h>
//每个函数是相互独立的
void swap(int x,int y);
void swap(int x,int y)
{
int temp;
printf("在swap中互换前:x = %d, y = %d\n",x,y);
temp = x;
x = y;
y = temp;
printf("在swap中互换后:x = %d, y = %d\n",x,y);
}
int main()
{
int x,y;
printf("请输入两个整数:");
scanf("%d%d",&x,&y);
printf("在main中互换前:x = %d, y = %d\n",x,y);
swap(x,y);
printf("在main中互换后:x = %d, y = %d\n",x,y);
return 0;
}
传指针
#include <stdio.h>
//每个函数是相互独立的
void swap(int *x,int *y);
void swap(int *x,int *y)
{
int temp;
printf("在swap中互换前:x = %d, y = %d\n",*x,*y);
temp = *x;
*x = *y;
*y = temp;
printf("在swap中互换后:x = %d, y = %d\n",*x,*y);
}
int main()
{
int x,y;
printf("请输入两个整数:");
scanf("%d%d",&x,&y);
printf("在main中互换前:x = %d, y = %d\n",x,y);
swap(&x,&y);
printf("在main中互换后:x = %d, y = %d\n",x,y);
return 0;
}
传数组
#include <stdio.h>
void get_array(int a[10]);
void get_array(int a[10])
{
int i;
for(i=0;i<10;i++)
{
printf("a[%d] = %d\n",i,a[i]);
}
}
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,0};
get_array(a);
return 0;
}
可变参数
- 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
- 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
- 使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。宏 va_start 是在 stdarg.h 头文件中定义的。
- 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。
- 使用宏 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;
}
int 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));
}
30.指针函数和函数指针
指针函数
#include <stdio.h>
char *getWord(char);
char *getWord(char c)
{
switch(c)
{
case'A':return"Apple";
case'B':return"Banana";
case'C':return"Cat";
case'D':return"Dog";
default: return"None";
}
}
int main()
{
char input;
printf("请输入一个字符:");
scanf("%c",&input);
printf("%s\n",getWord(input));
return 0;
}
- 使用指针变量作为函数的返回值,就是指针函数
不要返回局部变量的指针
局部变量是函数内的 不能被带出函数外 所以会编译报错
#include <stdio.h>
//编译失败
//原因:不能返回局部变量
char *getWord(char);
char *getWord(char c)
{
switch(c)
{
char str1[] = "Apple";
char str2[] = "Banana";
char str3[] = "Cat";
char str4[] = "Dog";
char str5[] = "None";
case'A':return str1;
case'B':return str2;
case'C':return str3;
case'D':return str4;
default: return str5;
}
}
int main()
{
char input;
printf("请输入一个字符:");
scanf("%c",&input);
printf("%s\n",getWord(input));
return 0;
}
函数指针
- 指针函数 *int p();
- 函数指针 *int (p)();
#include <stdio.h>
int square(int);
//square自定义求平方函数
int square(int num)
{
return num * num;
}
int main()
{
int num;
int (*fp)(int);
//定义一个函数指针 输入类型为int
printf("请输入一个整数:");
scanf("%d",&num);
fp = square;
printf("%d * %d = %d\n",num,num,(*fp)(num));
return 0;
}
函数指针作为参数
函数指针可以作为一个参数传递给另一个函数。这时函数指针的使用就像普通的常量和变量一样。当函数指针作为参数传递的时候,这时接收参数传递的函数通常需要根据这个指针调用这个函数。作为参数传递的函数指针通常表示回调函数(Callback Functions)。
#include <stdio.h>
int add(int,int);
int sub(int,int);
int calc(int (*fp)(int,int),int,int);
//地址函数 计算地址运算
int add(int num1,int num2)
{
return num1 +num2;
}
int sub(int num1,int num2)
{
return num1 - num2;
}
int calc(int (*fp)(int,int),int num1,int num2)
{
return(*fp)(num1,num2);
}
int main()
{
printf("3 + 5 = %d\n",calc(add,3,5));
printf("3 - 5 = %d\n",calc(sub,3,5));
return 0;
}
函数指针作为返回值
举例:现在让用户输入一个表达式,然后程序根据用户输入的运算符来决定调用add还是sub函数进行运算
#include <stdio.h>
int add(int ,int);
int sub(int ,int);
int calc(int (*fp)(int,int),int,int);
int (*select(char op))(int,int);
int add(int num1,int num2)
{
return num1 + num2;
}
int sub(int num1,int num2)
{
return num1 - num2;
}
int calc(int (*fp)(int,int),int num1,int num2)
{
return (*fp)( num1, num2);
}
int (*select(char op))(int ,int )
{
switch(op)
{
case'+':return add;
case'-':return sub;
}
}
int main()
{
int num1,num2;
char op;
int (*fp)(int,int);
printf("请输入一个式子(如1+3):");
scanf("%d%c%d",&num1,&op,&num2);
fp = select(op);
printf("%d %c %d = %d\n",num1,op,num2,calc(fp,num1,num2));
return 0;
}
31.局部变量和全局变量
不同函数的变量无法相互访问
符合中变量作用范围不同
#include <stdio.h>
int main()
{
int i = 520;
printf("before,i = %d\n",i);
for(int i = 0;i < 10;i++)
{
printf("%d\n",i);
}
printf("after,i = %d\n",i);
return 0;
}
全局变量
如果不对全局变量初始化 会自动初始化为0
#include <stdio.h>
//全局变量的定义和使用
void a();
void b();
void c();
int count = 0;
void a()
{
count++;
}
void b()
{
count++;
}
void c()
{
count++;
}
int main()
{
a();
b();
c();
b();
printf("小郭今天被抱了%d次\n",count);
return 0;
}
如果在函数的内部存在一个 与全局变量同名的局部变量,编译器不会报错,而是在函数中屏蔽全局变量(也就是说**在这个函数中,全局变量不起作用)**。
#include <stdio.h>
void func();
int a,b = 520;
void func()
{
int b;
a = 880;
b = 120;
printf("In func, a = %d,b = %d\n",a,b);
}
int main()
{
printf("In main, a = %d,b = %d\n",a,b);
func();
printf("In main, a = %d,b = %d\n",a,b);
return 0;
}
extern关键字
用extern关键字告诉编译器:这个变量我在后面定义了,你先别急着报错!
#include <stdio.h>
void func();
void func()
{
extern count;//防止报错
count ++;
}
int count = 0;
int main()
{
func();
printf("%d\n",count);
return 0;
}
不要大量的使用全局变量:
- 占用内存多,从全局变量定义开始,到程序退出才被释放
- 会污染命名空间,降低程序的可读性
- 提高了程序的耦合性,牵一发而动全身,时间一久不容易知道全局变量被哪些函数修改过。
32.作用域和链接属性
作用域
当变量被定义在程序的不同位置时,它的作用范围是不一样的,这个作用范围就是我们所说的作用域。
C语言的四种作用域:
- 代码作用域
- 作用范围是从变量定义的位置开始,到标志该代码块结束的右大括号” }”
- 形参同样是代码作用域
- 文件作用域
- 任何在代码块之外声明的标识符都具有文件作用域
- 作用范围是从声明位置开始,到文件的结尾处都是可以访问的
- 函数名也具有文件作用域,因为函数名本生也是在代码块之外
- 原型作用域
- 只适用于函数原型中声明的参数名
- void func(int a,int b,intc) a,b,c就是原型作用域
- 函数作用域
- 只适用于goto语句的标签,作用将goto语句的标签限制在同一个函数内部,以防止出现重名标签。
#include <stdio.h>
//全局变量 文件作用域
void func();
int main()
{
extern int count;
func();
count++;
printf("In main,count = %d\n",count);
return 0;
}
int count;
void func()
{
count++;
printf("In func,count = %d\n",count);
}
定义和声明
- 定义:编译器为变量申请内存并填充一些值 (坑)
- 声明:编译器知道该变量被定义在其它地方
- 局部变量既是定义又是声明
链接属性
- external(外部的):多个文件中声明的同名标识符表示同一个实体
- internal(内部的):单个文件中声明的同名标识符表示同一个实体
- none(无):声明的同名标识符被当作独立不同的实体
- 只有具备文件作用域的才能拥有external或internal的链接属性,其它作用域的标识符都是none属性。
33.生存期和存储类型
生存期
C语言的变量有两种生存期:
- 静态存储期
- 自动存储期
存储类型
C语言五种不同的存储类型:
- auto
- 自动变量
- 在代码块中声明的变量默认的存储类型就是自动变量,使用关键字auto来描述
- register
- 寄存器变量
- 将一个变量声明为寄存器变量,那么该变量就有可能被存放在CPU的寄存器中。
- 寄存器变量大致等于自动变量
- 注意:寄存器变量没有办法通过取地址运算符获得该变量的地址。
- static
- 静态局部变量
- 使用static来声明局部变量,那么就可以将局部变量指定为静态局部变量。
- 直到程序结束才会被释放。
- extern
- typedef
34.递归
汉诺塔游戏
目录树索引