函数-指针-数组

发布于 2022-05-06  142 次阅读


函数

函数调用有先后顺序,需要先定义才能调用,但是一般情况下我们会将函数声明在头文件中,方便随时调用

这里分为形式参数和实际参数

形式参数就是形式上定义的一个参数,实际参数是实际将其赋值的参数

函数类型和函数返回

void 是空类型,不需要return返回

return:返回值,返回的类型必须与函数类型相同

递归:函数自己调用自己

这里我们举个例子

此时会一直循环一个数字,因为在Str01函数中,if语句内,Str01传参为a++,每次自增1,但是++自增符号在后面,所以它是先传参给Str01的参数a,再进行自增,但是银行它后自增,还没有进行自增,语句就跳出去了,所以一直打印的为0

递归不要太深,否则就会引起栈溢出

数组

10个元素,每一个元素都是一个char,占用一个字节

注意

在只声明数组而不进行初始化时,它在内存中不是00,而当我们进行初始化操作,将其第六位(因为是从0开始,5就是第六位)元素赋值为a时,其他元素所占字节就会变成00

这样定义数组的方式也可以,其会根据赋值元素的数量自动判断数组元素有多少

这样定义,元素为6个,会根据最后一个元素判断

数组越界错误

我们定义的数组a,然后一共只有4位,我们这个时候printf函数打印数组第五位,这个时候就会产生数组越界错误,其取的是第五位的内存随机值

二维数组

指针

指针符号:* &

*:取值符号

&:取地址符号

内存概念:

在32位操作系统下,每一个进程都有4GB的内存空间(虚拟内存),从物理内存映射过来的虚拟内存

2GB是用户空间,2GB是内核空间(共享的)

在64位操作系统下,可以完整访问到4GB内存的

32位程序的地址最大长度是32位

64位程序的地址最大长度是64位

指针类型要和指向的数据类型一致

指针变量的变量名 = 地址

我们定义了一个指针变量p,它等同于数组c,而数组名字又等于其内存首地址,那么我们打印p[0],就等于打印数组c的0位的元素

取下一个变量

p+1即可

p = 地址

*p:取地址上的值

指针+1加的是其类型长度

所以指针+1 = p+1= p+ sizeof(int)

在内存上面来看,int类型的数据宽度为4字节,那么p的地址加上int的4字节,也就是取原数组中的第二个元素值

数组类型和其他类型不同,数组名称直接指向地址,所以无需求地址符号

但是int等其他类型需要求地址符号,让我们的指针变量p等于它的地址

使用指针修改变量值

指针小实例

我们上面定义一个主函数main,它返回的是int类型

下面定义一个函数test2,形参为a,b,c,都为int类型,c的形参是其内存上的值

此时我们test2函数中的代码为

c的内存上的值 = a +b

我们主函数做一个操作:

定义一个int类型nRet变量,其初始化值为0

然后我们调用test2函数,传参给他,此时我们的c传参过去的是nRet的地址

然后我们打印nRet的值,为3

是因为我们nRet的地址对应了c,此时c的内存上的值又等于a+b

这个时候就改变了我们nRet原有的值

指针和数组实例

过程:

首先两个函数,main和test2

test2中定义两个形参,为int类型,同时为指针变量ArrStart,ArrEnd

然后test2中做了一个循环相加

int类型变量add初始化值为0

同时while循环语句,条件为ArrStart小于End

循环体如图

main函数中

我们定义一个数组c,其含有5个元素

同时定义一个int变量nE,等于test2的返回值

我们调用test2并传参,将数组c传参给*ArrStart,相当于此时ArrStart内存地址上的值为c数组

我们再给*ArrEnd传参,传参值为c+5,数组c相当于一个指针,那么我们+5相当于加5个int类型的长度,就是数组结束的地方

传参后打印nE,也就是打印test2返回的值

同时test2中的循环体做了一个加法运算,并且ArrStart自增,每次自增1,相当于这个指针每次循环加了一个int类型的数据宽度

相当于每次循环,ArrStart自动依次取数组的值并进行相加

结果为15

解引用

int a =1;

int *p;

p = &a;

以上的p=&a就是解引用的过程

注意

指针默认是没有指向内存的

例如我们的int a = 50; 这样是没有问题的,因为int a在声明变量的时候就已经开辟了内存空间

但是指针不是,其默认没有开辟空间

所以不能

int *p;

*p =50;

这样是不行的

同时如果

int *p = NULL;

*p= 50;

这样也是不行的

指针指向二维数组

这里我们定义一个二维数组,其每个数组包含了4个元素

我们下面定义一个数组指针,名为p的指针变量,该指针指向了一个三个元素的数组

然后我们让其等于多维数组c

这个时候,我们定义了其指向三个元素,也就是可以这样理解:三个为一个组

下面打印时,每次加三个int的宽度

例如我们有一个数组为:

{1,2,3}

{4,5,6}

{7,8,9}

然后我们定义

int (*p)[3] 三个元素为一组

我们这时打印*p[0] 得出1

*p[1] 得4

指针指向三维数组

我们这里定义一个三维数组

用法其实与二维数组差不多

我们定义完成后

(*p)[3][4]的意思是z轴默认3个,然后4个为一个一维数组

与二维数组类似

如果我们这里z轴写4个,然后打印时我们打印4

就会数组溢出

遍历二维数组

我们这里定义一个int函数,名为Arr1,形式参数为int a[][3],account

a[][3],是一个元素为3的二维数组

然后做for循环,再嵌套一层for

外for循环,循环的条件是多少行(一共三行)

里层for循环条件的是元素数量

同时打印二维数组a

main函数传参给Arr1,传入参数为二位数组c和3

过程理解:

传入参数后,a此时就是相当于二维数组c

外层循环条件中,i<account,account为3,也就是二维数组中一共有三行

里层循环条件中,k<3,这里的3是元素数量

同时打印a

就能遍历出二位数组的每个值

数组保护

数组也可以使用const只读函数来进行保护

保护后,数组为只读,不可修改(不绝对,可以在内存上进行修改)

变参函数

首先需要include包含stdarg.h

我们平常定义的函数都是固定传参,而变参函数可以变化参数

首先我们定义一个函数printStr(int a,...) 这里定义的a是参数数量,...是不限制参数数量

然后我们引用va_list函数,其可以实现变参(是一种宏)

va_list需要开始结束

va_start va_end

写好以后

做了一个for循环,因为我们要相加的参数为3个,所以a为3

所以条件中i<3

定义一个Ntemp用来做加法

va_arg返回值是不固定参数,用来遍历所有参数

然后我们变参函数写好后,return返回 nTemp的值

同时我们主函数中定义一个int变量b,来接收

传参给printStr函数,3为参数数量,后面的可以随便更改参数

打印 得到三个数相加的结果