目录
一、指针函数和函数指针
1.指针函数
- 使用指针变量作为函数的返回值,就是指针函数。
注意:不要返回局部变量的指针!!!
代码举例:
#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;
}
运行结果:
2.函数指针
- 指针函数 --> int *p();
- 函数指针 --> int (*p)();
代码举例:
#include <stdio.h>
int square(int);
int square(int num)
{
return num * num;
}
int main()
{
int num;
int (*fp)(int);
printf("请输入一个整数:");
scanf("%d",&num);
fp = square;
printf("%d * %d = %d\n", num, num, (*fp)(num));
}
运行结果:
3.函数指针作为参数
代码举例:
#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;
}
运行结果:
4.函数指针作为返回值
代码举例:
#include <stdio.h>
int add(int, int);
int sub(int, int);
int calc(int (*)(int,int),int,int);
int (*select(char))(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;
}
运行结果:
二、局部变量和全局变量
1.不同函数的变量无法相互访问
代码举例:
#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;
}
运行结果:
2.全局变量
- 在函数里边定义的叫局部变量;在函数外边定义的叫外部变量,也叫全局变量。
- 有时候,我们可能需要在多个函数中使用共同的一个变量,那么就会用到全局变量。因为全局变量可以被本程序中其他函数所共用。
代码举例:
#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;
}
运行结果:
- 如果不对全局变量进行初始化,那么它会自动初始化为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 func ,a = %d,b = %d\n",a,b);
func();
printf("In main ,a = %d,b = %d\n",a,b);
return 0;
}
运行结果:
3.extern关键字
- 用extern关键字告诉编译器:这个变量我在后边定义了,你先别急着报错!
代码举例:
#include <stdio.h>
void func();
void func()
{
extern count;//若没有该行代码则会报错
count++;
}
int count = 0;
int main()
{
func();
printf("%d\n",count);
return 0;
}
运行结果:
4.不要大量的使用全局变量
- 使用全局变量会使你的程序占用更多的内存,因为全局变量从被定义时候开始,直到程序退出才被释放。
- 污染命名空间,虽然局部变量会屏蔽全员变量,但这样一来也会降低程序的可读性,人们往往很难一下子判新出每个变量的含义和作用范围。
- 提高了程序的耦合性,牵一发而动全身,时间久了,代码长了,都不知道全局变量被哪些函数修改过。
三、作用域和链接属性
1.作用域
- 当变量被定义在程序的不同位置时,它的作用范围是不一样的,这个作用范围就是我们所说的作用域。
- C语言编译器可以确认4种不同类型的作用域:代码块作用域、文件作用域、原型作用域、函数作用域
2.代码块作用域
- 在代码块中定义的变量,具有代码块作用域。作用范围是从变量定义的位置开始,到标志该代码块结束的右大括号 “ } ” 处。
- 尽管函数的形式参数不在大括号内定义,但其同样具有代码块作用域,隶属于包含函数体的代码块。
代码举例:
#include <stdio.h>
int main(void)
{
int i = 100;//i1
{
int i = 110;//i2
{
int i = 120;//i3
printf("i = %d\n",i);
}
// i = 110
{
printf("i = %d\n",i);
int i = 130;//i4
printf("i = %d\n",i);
}
printf("i = %d\n",i);
}
printf("i = %d\n",i);
return 0;
}
运行结果:
3.文件作用域(file scope)
- 任何在代码块之外声明的标识符都具有文件作用域,作用范围是从它们的声明位置开始,到文件的结尾处都是可以访问的。
- 另外,函数名也具有文件作用域,因为函数名本身也是在代码块之外。
代码举例:
#include <stdio.h>
void func(void);
int main(void)
{
extern int count;
func();
count++;
printf("In main,count = %d\n",count);
return 0;
}
int count;
void func(void)
{
count++;
printf("In func,count = %d\n",count);
}
运行结果:
4.原型作用域(prototype scope)
- 原型作用城只适用于那些在函数原型中声明的参数名。函数在声明的时候可以不写参数的名字但参数类型是必须要写上的),其实函数原型的参数名还可以随便写一个名字,不必与形式参数相匹配(当然,这样做没有任何意义!)。
5.函数作用域(functiion scope)
- 函数作用域只适用于goto语句的标签,作用将goto语句的标签限制在同一个函数内部,以及防止出现重名标签。
6.定义和声明
- 当一个变量被定义的时候,编译器为变量申请内存空间并填充一些值。
- 当一个变量被声明的时候,编译器就知道该变量被定义在其他地方。
- 声明是通知编译器该变量名及相关的类型已存在,不需要再为此申请内存空间。
- 局部变量既是定义又是声明。
- 定义只能来一次,否则就叫做重复定义基个同名变量;而声明可以有很多次。
7.链接属性
(1)external(外部的)
- 多个文件中声明的同名标识符表示同一个实体
(2)internal(内部的)
- 单个文件中声明的同名标识符表示同一个实体
(3)none(无)
- 声明的同名标识符被当作独立不同的实体
注意:
- 只有具备文件作用域的标识符才能拥有external或internal的链接属性,其他作用域的标识符都是none属性。
- 默认情况下,具备文件作用域的标识符拥有external属性。也就是说该标识符允许跨文件访问。对于external属性的标识符,无论在不同文件中声明多少次,表示的都是同一个实体。
- 使用static关键字可以使得原先拥有external属性的标识符变为internal属性。这里有两点需要注意:
① 使用static关键字修改链接属性,只对具有文件作用域的标识符生效(对于拥有其他作用域的标识符是另一种功能)
② 链接属性只能修改一次,也就是说一旦将标识符的链接属性变为internal,就无法变回external了。