C语言——指针函数和函数指针、局部变量和全局变量、作用域和链接属性

目录

一、指针函数和函数指针

1.指针函数

2.函数指针

3.函数指针作为参数

4.函数指针作为返回值

二、局部变量和全局变量

1.不同函数的变量无法相互访问

2.全局变量

3.extern关键字

4.不要大量的使用全局变量

三、作用域和链接属性

1.作用域

2.代码块作用域

3.文件作用域(file scope) 

4.原型作用域(prototype scope)

5.函数作用域(functiion scope)

6.定义和声明

7.链接属性


一、指针函数和函数指针

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了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值