1.1传值调用和传址调用
这里我们举一个例子,完成交换变量a和b的值。

从上述代码中,可以看出交换前后变量a,b的值并未发生交换,我们在将变量a,b的值传给swap函数后,x,y接受到a和b,在swap函数内部,x,y成功交换,而a,b未交换。在这里,就与函数调用过程中的传参有关。
我们在函数调用过程中,往往会传递参数,那么也就有一方会接受参数。前者称为实参,后者成为形参。实参,也称实际参数,是在调用时传递给函数的参数,参数可以是常量,变量,表达式,函数等。形参,也称形式参数,是在定义函数名和函数体时使用的参数。在调用过程中,实参将赋值给形参。所以二者的关系 可以概括为:形参是实参的临时拷贝。
因此,x,y只是a和b的一份临时拷贝,通过改变x,y,对a和b的值没有影响。
对代码进行改进如下:

这里我们在传参的过程中,传递的是地址,形参部分用指针接受,这样就可以通过pa,pb指针变量对x,y进行交换。
1.2模拟实现strlen函数
首先,strlen是求字符串长度的库函数,他需要包含的头文件是#include <string.h>
int main()
{
char arr[10]="abcdef";
int k=strlen(arr);
printf("%d",k);
}在计算过程中,每记录一个字符,计数器就加加,字符串的结束标志是'\0',当遇到'\0'时停止。
下来我们通过指针模拟实现一个strlen功能的函数。

通过自定义函数my_strken求字符串长度,形参用字符指针变量接收arr,count作为计数器,记录字符个数,当记录到’\0'时,循环停止,返回count;
1.1一维数组
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int* p = arr;
for (int i = 0; i < sz; i++)
printf("%d ", *(p + i));
}在这里,数组名表示数组首元素地址,这里创建一个指针变量p接收,p中存放arr[0]的地址。
对p进行加1,可以跳过4个字节,访问下一个元素地址,解引用找到这个元素。这样就可以访问整个数组元素。
2.2数组指针
整形指针,就是存放整形变量的地址。 字符指针,就是存放字符变量的地址。 因此,数组指针,就是存放数组的地址。
数组指针的定义,首先它是一个指针,就得先于“*”结合,证明他是一个指针,再与[10]结合,这证明他所指向的对象是数组。这与整型指针一样,int*p, p先于*结合,证明他是指针,再与int结合,证明它所指向的对象是整形数据(int)。
代码展示:
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int (*p)[10]=&arr;
for(int i=0;i<10;i++)
printf("%d ",(*p)[i]);
}上述代码也可以访问数组,但整体不如前面代码方便简洁。所以数组指针一般不用到一维数组,而是与二维数组一起用。
2.3数组指针与二维数组
我们在访问一维数组时,是通过他的数组名来进行访问的,这里二维数组也一样。
一维数组的数组名表示首元素地址,同样,二维数组的数组名也表示首元素地址。
而对于二维数组来说,首元素地址其实是第一行的地址,而第一行是可以看作是一个一维数组。
代码实现:

其中,打印的时候,三种情况都可以。
简单来说,二级指针就是用来存放一级指针地址的指针。
int a=10;
int* p1=&a;
int** p2=&p1;对指针变量p2来说,它先于*结合,证明他是一个指针,再与int*结合,证明它所指向的对象是整形指针类型,是一个二级指针。
类比:
整形数组,存放整形的数组。
字符数组,存放字符的数组。
指针数组,存放指针的数组。
int* arr[10];//arr先于[10]结合,说明它是一个数组,再与int*结合,说明它的元素类型是int*指针数组模拟二维数组

这里,arr1就是一维数组arr1首元素地址, 同理,arr2,arr3一样。
int arr1[3]={1,2,3};
int arr2[3]={2,3,4};
int arr3[3]={3,4,5};
int *arr[3]={arr1,arr2,arr3};