C语言语法基础--S2函数和指针


文章主要是针对计算机基础二级知识点内容而言;

1 函数

1.1 库函数

努力多使用标准库函数,既标准又快速移植性又强;
要求:只需要学会能看懂库函数并且学会调用即可;

1.1.1 库函数及其调用

一般形式:函数名(参数列表)
**前提一定是使用文件包含 #include “”/<> 最后千万不要加分号。

  • 出现在表达式中 y=sin(x);
  • 作为独立的的语句完成某种操作 printf("*\n");

1.2 函数定义

  • 函数时C语言程序的基本功能模块,用于完成一项相对独立的任务。一个C语言中由若干个函数构成,但main函数有且只有一个。函数时程序的最小组成单位。
  • 所有函数之间的关系是平行的,没有从属的概念。即定义不能在函数内部嵌套定义,但是可以函数嵌套调用。函数的平行概使得函数的编写相对独立,便于模块化程序的实现

1.2.1 函数定义形式

  1. 函数定义的一般形式
    函数返回值类型 函数名(类型名 形式参数1, 类型名,形式参数2,…){
    // 函数说明部分
    函数体

}
若省略返回值类型则为默认为int类型返回值

  • 不能在函数的内部定义函数,函数名和形式参数都是由用户命名的标识符。在同一程序中,函数名必须唯一,不能出现重名的情况。 形式参数名只要在同一函数中唯一即可,可以与其他函数中的变量同名。
    【函数举例】
#inlcude <stdio.h>
#include <math.h>
float fun1(float x,float y);

main(){
	float a,b,c,d;
	scanf("%f,%f",&a,&b);
	c=fun1(a,b);
	d=fun1(b,a);
	printf("%f,%f",c,d);

}

1.3 函数参数和返回值

参数传递有值传递和地址传递两种;函数定义的参数列表称为形式参数,调用函数时引进的参数称为实际参数。

1.3.1 值传递和地址传递

在定义函数时,函数名后面的参数列表称为形式参数。
在主调函数中,函数名后面括号中的参数称为实际参数。

  • 值传递:实参复制到形参,不同的内存单元,指互不影响
  • 地址传递:操纵的是同一块内存空间上的数;地址传递有:指针传递和引用传递;

1.3.2 函数返回值

函数的值通过return语句返回,return语句一般形式:

  • return 表达式;或 return(表达式);return语句中的表达式的值就是所求的函数值,返回的类型必须与函数定义的类型一致。若不一致,会自动转换。
    在一个函数体内,可以在多处出现return语句,但是无论函数体中有多少个return语句,return语句都只可能会被执行一次
  • return ;后面不含表达式,但此时必须定义为void类型,作用只是使流程返回到调用函数的位置。
  • 函数体内没有return语句,这时必须定义为函数为void类型,执行完语句体,然后返回调用函数。

1.4 函数调用

  • 一个C程序中主要有一个主函数和若干子函数组成,主函数使用被调函数的功能,称为对被调函数的调用。
  • 函数调用是通过函数名称和函数参数的组合使用来实现的。
  • 一个函数可以被主函数调用,也可以被其他函数调用,各函数之间可以相互进行调用;

1.4.1 函数调用

函数调用分为 有参数调用和无参数调用;

  1. 一般形式
  • 函数名(参数列表);
  • 函数名();
  1. 函数调用语法
  • 调用函数时,函数名与所调用的函数名字完全一致;
  • 实参可以是表达式,在类型上按照位置与形参一一对应;
  • 函数先申明,再使用,后定义;
  • 函数直接或者间接地调用自己,称为递归调用;
    程序递归调用就是使用栈的技术,一个个使用完之后再返回
    【例子】
#include<stdio.h>
main(){
	int i=1,p;
	p=f(i,i+1);
	printf("%d\n",p);

}
int f(int a,int b){
	int c;
	c=a;
	if(a>b){
		c=1;
	}
	else if(a==b){
		c=0;
	}
	else{
		c=-1;
	}
	return(c);
}
  1. 函数的申明和定义
    定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等。是一个完整的、独立的函数单位。
    函数申明的作用:是利用它在程序的编译阶段对调用函数的合法性进行全面检查。它把函数名、函数类型以及形参的类型、个数和顺序告知编译系统,以便在调用该函数时系统对此进行对照检查。
  • 函数申明一般形式:
    类型名 函数名(参数类型1,参数类型2,…)
    或者:
    类型名 函数名(参数类型1 参数名1,参数类型2 参数名2,…)
    【例如】double add(double x, double y){…} //申明加定义
    double add(double,double); // 申明
    double add(double x, double y); //申明

1.4.2 递归调用

在调用一个函数的过程中又出现或间接得调用该函数本身的,称为函数的递归调用;
【程序实例】

#include <stdio.h>
long fun(int);
main(){
	printf("\n %ld",fun(4))

}
long fun(int x){
	if(n==1 && n==2){
		s=2;
	}
	else{
		s=n+fun(n-1);
	}
	return s;
}

1.5 全局变量和局部变量

  1. 全局变量:全局变量是指在函数外部定义的变量;即main函数外部定义的变量;不是属于哪一个函数,都可以被函数共用,但是在函数内部会用同名作用域屏蔽。
    全局变量都可以被所有函数共用和改变,如果一个函数中改变了全局变量的值,就会影响到其他函数
  2. 局部变量:局部变量是指在函数内部或复合语句内部定义的变量。
    局部变量只在定义它的函数或复合语句范围内有效。
    形参变量属于被调用函数的局部变量;实际参数属于主调函数的局部变量。
  3. 函数间是平行关系,局部变量不能相互调用,局部变量名是在不同函数之间是可以同名的。

1.5.1 变量存储类型及生存期

变量时数据的传递者,具有操作属性和存储类别两种属性。存储类别:auto、static、register、extern。
静态变量:可以一直继续存值;
寄存器变量:访问速度更快,属于自动类变量;
extern:向程序外拓展。

2 指针

2.1 基本概念

基本数据类型:是指抽象出来的原子的一个数据类型。
数组、结构体、… :都是大量数据类型组织起来的结构。
地址:计算机内存是以字节为单位的一片连续的存储空间,每一个字节都有一个编号,这个编号就称为内存地址。形象比喻:宿舍就是内存单元;宿舍号就是内存单元的地址;学生就是内存单元的内容;内存的存储空间是连续的,内存中的地址号也是连续的。

  • 指针:指针的实质就是地址。通过指针可以找到以它为地址的内存单元。

2.2 指针变量

2.2.1 指针变量的定义和引用:

指针变量就是用来存放内存地址的。
【例如】:int *p=a; 将变量a的内存地址(1012)存放到变量p中,要访问变量a所代表的存储单元,可以先找到变量p的地址2002,从中取出a的地址1012,然后再去访问以1012为首地址的存储单元。
通过变量p间接得到变量a的地址,然后再存取变量a的值的方式称为"间接存取"方式;用来存放地址的变量称为"指针变量"。

  1. 指针变量的一般定义形式
    类型名 指针变量名1 ,指针变量名2,…;【例如】int p1;intp2;
  • 星号紧跟数据类型,说明指针变量指向的数据类型
  • p1,p2是两个指向整型(int类型)变量的指针,就是说变量p1,p2中只能存放int类型变量的地址。
  • 变量值(指针)所指向的变量的数据类型称为"基类型"。
  1. 对指针变量的操作
    指针运算符:取地址运算符&和取内容运算符*。
    & <变量名> 表示取变量的内存地址;只能用于一个具体的内容或者数组元素,不能是表达式或者常量。
  • <指针变量名> 表示指针变量所指的内容;

2.2.2 指针变量的初始化和与运算

  1. 指针变量的初始化
    指针变量在初始化之前必须对其进行初始化,使得指针变量指向一个确定的内存单元,否则会造成野指针。
    指针变量的初始化一般格式形式:
    类型名 指针变量名 = 初始化地址值
    char ch;
    char *p_ch=&ch;
  • 任意类型的指针变量都要遵守"先定义,再初始化,后使用"的原则。未经初始化的指针禁止使用;
  • 必须使用同一类型数据的地址进行指针初始化;
  • 不能把一个整数赋值给指针变量。
  1. 指针的运算
  • 通过求地址运算符&获得地址值
  • 通过指针变量获得地址值
    int k=1,*q,*p;
    q=&k;
    p=q; // 使得两个指针指向同一个地址
  • 进行赋值运算时,赋值号两边的指针类型必须相同。
  1. 通过标准库函数获得地址值
    通过调用库函数malloc和calloc在内存中开辟动态存储单元,并把所开辟的动态存储单元的地址赋给指针变量。
  2. 给指针变量赋"空"值。
    int* p1 = NULL; //等价于p1=0;p1=’\0’;

2.3 数组和指针

用指针变量来指向数组中的首地址;通过首地址就可以依次找到其他数组元素,同样指针变量也可以指向数组中的任意元素。

2.3.1 指向数组元素的指针

数组的指针是指数组的首地址,数组元素的指针是各个数组元素的地址。数组名就是这块连续内存单元的首地址。

  1. 指向二维数组的行指针变量
    数据类型 (*指针变量)[n];
    【例如】 int (*p)[3] // 在二维数组中,可以使p分别指向a[0],a[1],a[2];
    指向数组的指针;和指针类型的数组;

2.3.2 通过指针引用数组元素

  1. 移动指针–指向数组元素
  2. *(p++)

2.4 字符串和指针

在C语言中,对于字符串没有专门的字符串类型类说明,一般都是使用字符类型的数组来存储字符串。使用指针对字符串进行运算。但是在C++中的库函数中,有定义好的tring类型,可以直接定义字符串类型。

2.4.1 字符指针

用字符指针指向一个字符串。
char* str=“I am a student.”; // 定义str为指针变量,并指向字符串的首地址
printf("%s\n",str);
【例子】

#include <stdio.h>
main(){
	char* p_str="beijing";	//定义指针p_str,并使其指向字符串"beijing"
	printf("%s\n",p_str);	//通过指针引用字符串的首地址来输出字符串
	while(*p_str){
		printf("%c",*p_str);	//通过指针引用每个字符来输出字符串
		p_str++;
	}
	printf("\n");
}
// 在程序中先采用格式符"%s"来输出字符串的格式,又通过改变字符串指针变量的值依次输出字符串的字符。

2.4.2 字符串指针作函数参数

将一个字符串从一个函数传递到另一个函数,可以用地址传递的方法,即用字符数组名作为参数或用指向字符串的指针变量作为参数进行传递。

#include <stdio.h>
void fun(char*);

main(){
	gets(s);
	fun(s);
	puts(s);
}

void fun(char *c){
	while(*c){
		if(*c>='a'&&c<='z'){
			*c=*c-('a'-'A');
		}
		c++;
	}

}

2.5 函数和指针

2.5.1 用函数指针变量调用函数

  1. 函数指针
    在程序运行中,函数的代码是程序的指令部分,和数组一样也占用内存空间。编译时,系统会给每个函数分配一个入口地址,就是函数代码的内存单元你的首地址。函数名就是这个函数的首地址,可以使用指针变量指向函数参数的入口地址,这样的指针称为函数指针。

函数指针的定义格式形式:
数据类型(指针变量名)(形参列表);
【区别】
int
fun(int a,int b); // 这个函数返回值指向整型变量的指针;
int (*fun)(int a ,int b); // 定义了一个指向函数的指针,而这个函数的返回值类型时整型。
2. 用函数指针变量调用函数
一般形式:在给函数指针变量赋值时,只需给出函数名而不必给出参数。
int (*s)();
s=fun; // fun为已有定义的有参函数
因为是将函数入口的地址赋给s,不涉及参数的问题,不能写成:s=fun(a,b);

  • 用函数指针变量调用函数时,只需将(*s)袋贴函数名即可;s为已经定义过的指向函数的指针变量名;(*s)之后的括号中根据需要写上实参。
  • 函数指针也需赋初值,才能指向具体的函数。函数名代替了该函数的入口,可以直接用函数名为函数指针变量赋值。
    【程序实例】
int fa(int x){
	return x*x;
}

int fb(int x){
	return x*x*x;
}
int f( int (*f1)() , int (*f2)() , int x){
	return f2(x)-f1(x);
}

main(){
	int i;
	i = f(fa,fb,2);
	printf("% d \n",i);

}
// 但是感觉这个功能很鸡肋,命名函数调用,直接使用函数名即可,为什么还要再使用函数指针。

2.5.2 函数返回指针类型值

函数值的类型不仅仅是基本数据类型,而且还可以是指针类型。

#include<stdio.h>
int *fun(int* ,int*); 	// 函数申明语句
main(){
	int* p,i,j;
	printf("Enter two number:");
	scanf("%d%d",&i,&j);
	p=fun(&i,&j);
	printf("i=%d,j=%d,*p=%d\n",i,j,*p);

}

int* fun(int* a,int* b){
	if(*a>*b){
		return a;
	}
	return b;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值