小工具知识网

当前位置: 首页 > 行业知识 > 【C语言】指针(二)

行业知识

【C语言】指针(二)

2026-11-06 02:04:52 来源:互联网转载

目录

一、传值调用和传址调用

二、数组名的理解

三、通过指针访问数组

四、一维数组传参的本质

五、指针数组

六、指针数组模拟实现二维数组


一、传值调用和传址调用

指针可以用在哪里呢?我们看下面一段代码:

#include void Swap(int x, int y){int z = x;x = y;y = z;}int main(){int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;}

运行结果如下:

我们发现,并没有完成交换,调试发现:

出现这样的原因:a和b是实参(是真实传递给函数的),x和y是形参,当实参ab传给形参xy时候,形参把实参数据临时拷贝了一份,x,y创建自己的独立空间,因为有自己独立的空间,跟a,b无关,所以修改形参不会影响实参。这种交换方式也叫传值调用。

所以说:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。

措施:可以将a,b的地址传给Swap函数,Swap函数里通过地址间接的操作main函数中的a和b,达到交换的效果。也就是传址调用。

代码如下:

#include void Swap(int* pa, int* pb)//用指针变量来接收{int z = *pa;*pa = *pb;*pb = z;}int main(){int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap(&a, &b);//传地址printf("交换后:a=%d b=%d\n", a, b);return 0;}

传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量。

  • 未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。
  • 如果函数内部要修改主调函数中的变量的值,就需要传址调用。

    二、数组名的理解

    数组名就是数组首元素(第一个元素)的地址。

    代码如下:

    但有两个例外:

    1. sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
    2. &数组名,这里的数组名表示整个数组,所以&数组名取出的是整个数组的地址

    除此之外,任何地方使用数组名,数组名都表示首元素的地址。

    可能会有疑问,为什么首元素地址(arr)跟整个数组地址(&arr)相同呢?

    代码如下:

    从值的角度来讲,地址就是一个编号,它们打印出来的地址一模一样,但是意义却不相同,操作arr和&arr带来的结果也是不一样的。

    如下代码:

    可以看出,&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和arr都是首元素的地址,类型是int*,+1就是跳过一个整型(元素)。
    但是&arr和&arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组的。

    也可以这么理解:

    arr与&arr都是指针,指针有两个要素:

    • 第一个是地址值,也就指向的位置,打印出来的就是地址值,arr与&arr的地址值是一样的。
    • 第二个是类型(所指向的数据类型),arr指向数组第一个元素,&arr指向数组arr,arr+1后的地址值会偏移一个元素的长度,&arr+1后的地址值会偏移一整个数组的长度,所以arr与&arr类型是不一样的。

      三、通过指针访问数组

      #include int main(){int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;//p存放的数组首元素的地址for (i = 0; i  

      可以发现,数组的下标引用操作符([ ])效果相当于解引用操作符(*)

      其实数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。

      四、一维数组传参的本质

      之前我们都是在函数外部计算数组的元素个数,那可以把函数传给一个函数后,在函数内部求数组的元素个数吗?

      我们来看一段代码:

      #include void test(int arr[]){int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);}int main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;}

      运行结果如下:

      发现sz1计算错误,函数内部没有正确获得数组的元素个数。

      原因:

      数组名是数组首元素地址,传递的数组名,本质上数组传参传递的是数组首元素地址。

      所以函数的形参部分理论上应该用指针来接收首元素的地址。那么在函数内部写sizeof(arr)计算的是一个地址的大小(单位字节),而不是数组的大小(单位字节)。

      正因为函数的参数部分本质是指针,所以在函数内部是没办法求数组元素个数的。

      代码如下:

      void test(int arr[10]) //==>arr[]  参数写成数组形式,本质上还是指针{printf("%d\n", sizeof(arr)); //计算⼀个指针变量的⼤⼩}void test(int* arr) //参数写成指针形式{printf("%d\n", sizeof(arr));}int main(){int arr[10] = {1,2,3,4,5,6,7,8,9,10};test(arr);return 0;}

      上面数组传参的本质是传递了数组首元素的地址,所以形参访问的数组和实参的数组是同一个数组。

      形参的数组是不会单独再创建数组空间的,所以形参的数组是可以省略掉数组大小的。

      总结:一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

      五、指针数组

      数组是一组相同类型元素的集合。数组有整形数组,字符数组.....

      指针数组:存放指针(地址)的数组。

      int* arr1[6];//存放整型指针的数组char* arr2[10];//存放字符指针的数组

      如下图:

      指针数组的每个元素是地址,又可以指向一块区域。

      六、指针数组模拟实现二维数组

      代码如下:

      #include int main(){int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };//数组名是数组首元素的地址,类型是int*的,可以存放在parr数组中int* parr[3] = { arr1, arr2, arr3 };int i = 0;int j = 0;for (i = 0; i       

      parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型一维数组,parr[i][j]就是整型一维数组中的元素。

      上述的代码模拟出二维数组的效果,本质上其实不是二维数组。

      因为二维数组在内存中是连续存放的,而这三个数组在内存可不一定连续存放。

上一篇:解决方案要怎么写?

下一篇:服务器崩溃了怎么还原?