《算法笔记》2.6函数 2.7指针

一、学习概览

2.6函数

函数:实现一定功能的语句的集合。

函数
1.无参函数
2.有参函数
2.6函数
2.6.1函数的定义
2.6.2再谈main函数
整个函数一定从主函数的第一个语句开始执行
在需要调用其他函数时才去调用其他位置的函数
2.6.3以数组作为函数参数
2.6.4函数的嵌套调用
2.6.1函数的递归调用
自己调用自己

2.6.1函数的定义

  1. void——“空”。表示自定义函数只是单纯实现一些语句,而不返回变量。
    void printf1(){}
  1. return——C语言中使用return来返回函数需要传回的数据,且return后面的数据类型要和一开始给出的返回类型相同。
  2. 全局变量和局部变量:(注意:如果想让定义的变量对所有的函数都有用,最好还是使用全局变量的定义方式。)

1.全局变量:(推荐使用)
定义之后的所有程序段内都有效的变量**(定义在其之后所有函数之前)**。

2.局部变量:
定义在函数内部,且只在函数内部生效,函数结束时局部变量销毁

关于局部变量的一些专有名词:见局部变量
副本 值传递 形式参数(形参) 实际参数(实参)

  1. 传入多个参数时,用逗号“,”隔开。

2.6.2再谈main函数

  1. main函数返回0——告知系统 程序正常终止。

2.6.3以数组作为函数参数

  1. 数组作为参数时,第一维不需要填写长度,第二维需要。实际调用时也只需填写数组名。见数组作为函数参数
  2. 求解三个整数中的最大值时,可以先自定义一个比较两个数的函数,然后再调用两次(分别两次比较,每次比较两个变量)来实现。
  3. 每个字节(房间)都会有一个地址(房间号),计算机通过地址找到变量。
  4. 变量的地址:一般指它占用的字节中第一个字节的地址。

2.7指针

2.7指针
2.7.1什么是指针
变量在内存中如何存放
2.7.2指针变量
存放地址
改变+输出地址里存放的变量值
加减法
2.7.3
2.7.3指针与数组
1.枚举数组中的元素
2.指针的减法
2.7.4使用指针变量作为函数参数
1.把变量的地址传入函数
2.函数中将地址中的元素改变
原先数据也会被改变
2.7.5引用
1.引用的含义
2.指针的引用
注意区分引用&与地址运算符&
在编程时极为实用
传递参数的三种方式
1.值传递
2.6.1
2.7.4
2.地址传递
2.7.4
3.引用传递
2.7.5

2.7.1什么是指针

  1. C语言中用指针来表示内存地址 (或者称指针指向了内存地址),如果这个内存地址恰好是某个变量的地址,则称“这个指针指向该变量”。可以认为,指针就是变量的地址

2.7.2指针变量

  1. 只要在变量前面加上&,就表示变量的地址。&——取地址运算符。
  2. 非指针变量a的地址可以输出by &a:
    printf("%d, %d\n",&a,a);
  1. 指针是一个unsigned类型的整数。

1.整型的每一种都分为:无符号(unsigned)和有符号(signed)两种类型(float和double总是带符号的),在除char以外的数据类型中,默认情况下声明的整型变量都是有符号的类型char在默认情况下总是无符号的。在除char以外的数据类型中,如果需声明无符号类型的话就需要在类型前加上unsigned。
2. 无符号版本和有符号版本的区别就是无符号类型能保存2倍于有符号类型的正整数数据,比如16位系统中一个short能存储的数据的范围为-32768-32767,而unsigned能存储的数据范围则是0-65535。
3.由于在计算机中,整数是以补码形式存放的。根据最高位的不同,如果是1,有符号数的话就是负数;如果是无符号数,则都解释为正数。
4.另外,unsigned若省略后一个关键字,大多数编译器都会认为是unsigned int。

  1. 指针变量是用来存放指针(地址)的变量。定义时会在某种数据类型后加*来表示这是一个指针变量。
    注意:*放在变量名之前也可以。但C++程序猿更倾向于前一种写法。
    int* p;
    double* p;
    char* p;

    int *p1,*p2,*p3; //如果一次有多个同种类型的指针变量要同时定义,
//*只会结合于第一个变量名。此时为了美观,会把*放在变量名之前。
  1. 给指针变量赋值的方式:把变量的地址取出来,然后赋给对应类型的指针变量。
int a;
int* p=&a; //p的基类型为int

int a,b;
int *p1=&a,*p2=&b;
//注意:地址&a是赋值给p而不是*p的(星号是类型的一部分)。
//int*是指针变量的类型,p才是用来存储地址的变量名。
  1. 如何得到地址所指的元素:把*视为一把开启房间的钥匙,加在p的前面。
#include <stdio.h>
int main() {
   int a;
   int* p=&a; //指针变量p得到整型变量a的地址 
   a=233;
   printf("%d\n",*p); //用*打开p储存的房间号所对应的房间的门,得到里面变量的值 
   return 0;
}

//若直接对*p赋值,也可以改变保存的元素:
#include <stdio.h>
int main() {
   int a;
   int* p=&a; 
   *p=233;
   printf("%d, %d\n",*p,a); 
   return 0;
}

//若输出p,则输出的是变量a的存储地址:
#include <stdio.h>
int main() {
  int a;
  int* p=&a; //指针变量p得到整型变量a的地址 
  a=233;
  printf("%d\n",p); //用*打开p储存的房间号所对应的房间的门,得到里面变量的值 
  return 0;
}

在这里插入图片描述
若直接对*p赋值,也可以改变保存的元素:
在这里插入图片描述
若输出p,则输出的是变量a的存储地址:
在这里插入图片描述

  1. 指针变量的加减法(支持自增、自减)一般用于数组:减法——两个地址偏移的距离;p+1(p+i)——p所指的int型变量的下一(i)个int型变量地址(跨越4Byte或4iByte)。a+i等同于&a[i](a就是数组的首地址),*(a+i)等同于a[i]
    两个int型的指针相减,等价于在求两个指针之间相差了几个int(除以4——1个int占用4Byte)。(该解释对其他类型的指针同样适用。)
    scanf("%d",a+i); //输入数组元素的新颖写法
    printf("%d",*(a+i)); //输出
#include <stdio.h>
int main() {
   int a;
   scanf("%d",&a);
   printf("%d %d\n",a,&a); //输出变量存储的值,变量的地址
   return 0;
}

在这里插入图片描述
2. 基类型:指针变量存储的地址的类型。必须和指针变量存储的地址类型相同。

#include <stdio.h>
int main() {
	char a;
    char* p=&a; 
    *p='c';
    printf("%c, %c\n",*p,a); 
	return 0;
}

//会报错的代码
#include <stdio.h>
int main() {
	char a;
    int* p=&a;  //必须是char,和变量类型相同
    *p='c';
    printf("%c, %c\n",*p,a); 
	return 0;
}

在这里插入图片描述

2.7.3指针与数组

  1. 代码辨析
   int* p=&a; //a为普通变量
   int* p=a; //a为数组名,同时也是数组的首地址&a[0]。
   //数组名称也作为数组的首地址使用

2.7.4使用指针变量作为函数参数

  1. 使用指针变量作为函数参数时,是把变量的地址传入函数。因此,只有在获知地址的情况下对元素进行操作,才能真正地修改变量

2.7.5引用

  1. 引用:不使用指针,也能修改传入参数。
    不产生副本,只是给原变量常量不可以使用引用)起了个别名对引用变量的操作就是对原变量的操作。

  2. 引用的使用方法:会在某种数据类型后加&来表示这是一个引用变量。
    注意:考虑到引用是别名的意思,&一般放在变量名之前

  3. 不管是否使用引用,函数的参数名与实际传入的参数名可以不同

#include <stdio.h>
void change(int &x){
   x=1;
}

int main(){
   int a = 10;
   change(a);
   printf("%d\n",a);
   return 0;
}

在这里插入图片描述

  1. 如果读者阅读代码时碰到了引用,却对其含义不甚了解时:先去掉引用,看其原意是什么,再加上引用——这样会容易理解得多。

二、代码分析

局部变量

#include <stdio.h>
void change(int x){
	x=x+1;
}
int main(){
	int x=10; //这里也要改为a
	change(x); //x改为a也是同样结果,这句好像没啥用啊
	printf("%d\n",x); //这里也改为a
	return 0;
}

在这里插入图片描述

分析:

当在主函数中定义了x之后,将其作为 change()函数的参数传入,并令x加1,但是最后输出时x却仍然是10。

这是因为 change函数的参数x为局部变量,仅在函数内部生效,通过change(x)传进去的x其实只是传进去一个副本,也即 change函数的参数x和main函数里的x其实是作用于两个不同函数不同变量(虽然名字相同),取成不同的名字当然是可以的

这种传递参数的方式称为值传递,函数定义的小括号内的参数称为形式参数形参,而把实际调用时小括号内的参数称为实际参数或实参。

单向一次性值传递在传递参数时会产生一个副本,对副本的操作不会影响main函数中a、b的值

参数传递的三种方式:传值(value),传址(address),和传引用(reference)
1.传值时,子函数(被调用者)复制父函数(调用者)传递的值,这样子函数无法改变父函数变量的值
2.传址时,父函数将变量的地址传递给子函数,这样子函数可以能过改写地址里的内容改变父函数中的变量
3.传引用则是一种看起来像传值调用,而实际上功能同传址一样的传递方式。子函数可以改写父函数的变量值。

main函数也是一个函数!!!

数组作为函数参数

#include <stdio.h>
void change(int a[], int b[][5]){
	a[0]=1;
	a[1]=3;
	a[2]=5;
	b[0][0]=1;	
}

int main() {         //从这里开始执行
	int a[3]={0};    //数组定义要用大括号括起来
    int b[5][5]={0};
    change(a, b);
    for(int i=0;i<3;i++){
    	printf("%d\n",a[i]);
	}
	return 0;
}

在这里插入图片描述

分析:

注意,数组作为参数时,在函数中对数组元素的修改就等同于是对原数组元素的修改(这与普通的局部变量不同)。

虽然数组可以作为参数,但是却不允许作为返回类型出现。如果想要返回数组,则只能用上面的方法,将想要返回的数组作为参数传入

使用指针作为参数,交换两个数

#include <stdio.h>
void swap(int* a, int* b){
	int temp=*a;
	*a=*b;
	*b=temp;
}

int main(){
	int a = 1, b =2;
	int *p1=&a,*p2=&b; //取地址符
	swap(p1,p2);
	printf("a=%d,b=%d\n",*p1,*p2);
	return 0;
}

在这里插入图片描述

错误写法一:temp没有被初始化

void swap(int* a, int* b){
	int* temp;
	*temp=*a;
	*a=*b;
	*b=*temp;
}

在这里插入图片描述在这里插入图片描述

错误写法二:认为地址交换后元素就交换了

void swap(int* a, int* b){
	int* temp=a;
	a=b;
	b=temp;
}

其实函数作用的还是地址的副本。
在这里插入图片描述

用引用来修正“错误写法二”

#include <stdio.h>
void swap(int* &p1, int* &p2){ //引用 
	int* temp=p1;
	p1=p2;
	p2=temp;
}

int main(){
	int a = 1, b =2;
	int *p1=&a,*p2=&b; //取地址 
	swap(p1,p2); //不可以写成swap(&a,&b),因为常量不可以使用引用
	printf("a=%d,b=%d\n",*p1,*p2);
	return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值