0


【C语言进阶】——指针进阶[Ⅰ]

文章目录

1️⃣指针概念

1.指针就是个变量用来存放地址,地址唯一标识的一块内存空间。
2.指针的大小是固定的4/8个字节(32位平台/64平台)。
3.指针是有类型的,指针的类型决定了指针的+ - 整数的范围和指针解引用操作的时候的权限。
4.指针的运算。

1.字符指针

在指针的类型中有一种指针类型为字符指针 char ;*

一般使用:

#include<stdio.h>intmain(){char ch ='w';char* pc =&ch;//取ch地址放入pc中*pc ='c';//通过pc解引用把ch存入的数据改成'c'return0;}

还有一种使用方法:

intmain(){constchar* pstr ="hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?printf("%s\n", pstr);//显然不是!输出 hreturn0;}

** 代码:

const char* pstr = "hello bit."

特别容易认为是把字符串

hello bit

放到字符指针

pstr

里了,但本质上是把字符串

hello bit.

首字符的地址放到了

pstr

中。**
在这里插入图片描述

上面代码的意思是把一个常量字符串的首字符

h

的地址存放到指针变量

pstr

中。

🆚于是有了这样的面试题:

intmain(){char str1[]="hello bit.";char str2[]="hello bit.";constchar* str3 ="hello bit.";constchar* str4 ="hello bit.";if(str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if(str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return0;}

这里最终输出的结果是:
在这里插入图片描述
这里的

str3

str4

指向的是同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针,去指向同一个字符串的时候,它们实际会指向同一块内存,但是用相同的常量字符串去初始化不同的数组的时候,不同数组会开辟不同的内存块,所以

str1

str2

不同,

str3

str3

相同。

2.🅰️指针数组

**

指针数组是一个存放指针的数组

**

int* arr1[10];//整形指针的数组char* arr2[4];//一级字符指针数组char** arr3[4];//二级字符指针数组
举例:
int a =1;int* pa =&a;int* arr1[3]={pa};//arr1[0]访问pa的地址

-* ——————————————————*

3.🅱️数组指针

3.1数组指针的定义

**

数组指针是指针

**
整形指针

int* pa

能够指向整形数据的指针,那数组指针应该是:能够指向数组的指针。

int(*p)[10];

**解释:

p

先和

*

结合,说明

p

是一个指针变量,然后指针指向的是一个大小为10个整形的数组。所以

p

是一个指针,指向一个数组,叫数组指针。
这里要注意:

[]

的优先级要高于

*

号的,所以必须加上

()

来保证

p

先和

 *

结合。**

3.2 &数组名 🆚 数组名

对于下面的数组:

int arr[10];
 arr

是数组名,数组名表示数组首元素的地址。

 &arr

是什么呢?我们看一段代码:

#include<stdio.h>intmain(){int arr[10]={0};printf("%p\n", arr);printf("%p\n",&arr);return0;}

在这里插入图片描述
由此可见数组名 和 &数组名打印的地址是一样的。

难道两个真的一样吗?
再来看一段代码:

#include<stdio.h>intmain(){int arr[10]={0};printf("arr = %p\n", arr);printf("&arr= %p\n",&arr);printf("arr+1 = %p\n", arr+1);printf("&arr+1= %p\n",&arr+1);return0;}

在这里插入图片描述

根据上面的运行结果我们发现:其实数组名 和 &数组名,虽然值是一样的,但是意义应该不一样。

实际上:

&arr

表示的是整个数组的地址,而不是数组首元素的地址。(细品一下)
本例中

&arr

的类型是:

int(*)[10]

,是一种数组指针类型
数组的地址+1,跳过整个数组大小,所以

&arr+1

相当于

&arr

的差值是40。

**为什么

&arr+1

跳过40个字节?
因为:

arr

的类型是

int [10]

10个

int

相当于40个字节。**
数组的

类型

决定了+1/ -1 跳过几个字节。

3.3数组指针的使用

#include<stdio.h>intmain(){int arr[10]={1,2,3,4,5,6,7,8,9,0};int(*p)[10]=&arr;//把数组arr的地址赋值给数组指针变量p//但是我们一般很少这样写代码return0;}

一个数组指针的使用:一般使用在二维数组上

voidprint1(int(*pa)[5],int r,int c)//int (*pa)[5]一维数组指针接收{int i =0;for(i =0; i < r; i++){//pa+0指向第1行, + 1指向第2行...//+0找到第一个1维数组,+1找到第2个一维数组int j =0;for(j =0; j < c; j++){//printf("%d ", pa[i][j]);//等同于下列printf("%d ",*(*(pa+i)+j));// (pa+i)——>&arr+i找到第i行地址//*(pa+i)——>arr[i] //解引用找第i行数组名,相当于首元素地址//*(*(pa+i)+j)——>arr[i][j]//再解引用找到第i行第j个元素}printf("\n");}}intmain(){int arr[3][5]={1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};print1(arr,3,5);//二维数组的首元素地址是第一行//所以这里传参的是//相当于传了一个一维数组的地址return0;}

**你要知道:

int (*p) [5]
p

的类型是:

int(*)[5] 

,指向一个整形数组,数组有5个元素

p+1

跳过5 个

int

元素的数组**

学了指针数组和数组指针我们来一起回顾并看看下面代码的意思:

int arr[5];//arr是一个数组,数组有5个元素,每个元素是int型int*parr1[10];//parr是数组,数组有10个元素,每个元素是int*型int(*parr2)[10];//parr2是一个指针,指向一个有10个元素的数组,每个元素是int型,所以parr2是数组指针int(*parr3[10])[5];//parr3是一个数组,数组有10个元素,每个元素是int(*)[5],//该指针指向一个含有10个元素的数组,所以parr3是一个数组指针数组

**对

int (*parr3[10])[5];

不理解,可以看下列补充:**

在这里插入图片描述

4.数组参数、指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

4.1一堆数组传参

#include<stdio.h>voidtest(int arr[])//ok,数组大小可以不写{}voidtest(int arr[10])//ok{}voidtest(int*arr)//ok,整形地址放入整形指针{}voidtest2(int*arr[20])//ok,数组传参,形参可以数组也可以指针接收,20也可以省略{}voidtest2(int**arr)//ok,二级指针接收一级指针地址//数组名相当于首元素地址,arr2是int*类型的地址{}intmain(){int arr[10]={0};int*arr2[20]={0};//20个元素,每个元素int*..//数组名相当于首元素地址,arr2是int*类型的地址test(arr);//数组名相当于首元素地址test2(arr2);}

4.2二维数组传参

voidtest(int arr[3][5])//ok,二维数组接收{}voidtest(int arr[][])//NO,形参的二维数组,行可省,列不行{}voidtest(int arr[][5])//ok,行省了,列没省{}voidtest(int*arr)//NO,arr是二维数组,//首元素地址此时代表的是第一行的地址,相当于是一维数组//一维数组不能放入一级指针{}voidtest(int* arr[5])//NO{}voidtest(int(*arr)[5])//ok,指针指向5个元素,每个元素是int{}voidtest(int**arr)//NO,二级指针只能接收一级指针的变量的地址{}intmain(){int arr[3][5]={0};test(arr);//数组传参一般写成--数组名//除非传某个元素,——>&arr[1],arr[1]}

** 总结:
1 . 二维数组传参,函数形参的设计只能省略第一个 [ ] 的数字。
因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
这样才方便运算。
2 . 二维数组的数组名,表示首元素地址,其实是第一行的地址,第一行是一个一维数组
3.二级指针只能接收一级指针变量的地址**

4.3一级指针传参

#include<stdio.h>voidprint(int*p,int sz){int i =0;for(i=0; i<sz; i++){printf("%d\n",*(p+i));//*(p+i)==p[i]//(p+i),如果i=1,//+i跳过一个整形地址,再解引用,//就找到了相对应的元素}}intmain(){int arr[10]={1,2,3,4,5,6,7,8,9};int*p = arr;//1的地址赋给pint sz =sizeof(arr)/sizeof(arr[0]);//一级指针p,传给函数print(p, sz);return0;}

思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

voidtest1(int*p){}//test1函数能接收什么参数?intmain(){int a =10;test1(&a);//okint* pa =&a;test1(pa);//okint arr[5];test1(arr);//ok}

只要传给函数本质是一个指针,实参和形参类型能匹配上,就没问题。

4.4二级指针传参

#include<stdio.h>voidtest(int** ptr){printf("num = %d\n",**ptr);}intmain(){int n =10;int*p =&n;int**pp =&p;test(pp);//ok,本身是二级指针,传参二级指针接收test(&p);//ok,二级指针接收一级指针变量地址return0;}

思考:当函数的参数为二级指针的时候,可以接收什么参数?

voidtest(char**p){}intmain(){char c ='b';char*pc =&c;char**ppc =&pc;char* arr[10];test(&pc);//ok,二级指针接收一级指针变量地址test(ppc);//ok,本身是二级指针,传参二级指针接收test(arr);//Ok?//ok,每个元素是int*,首元素地址就是int*return0;}//三级指针解引用也可以....四级....五级....

在这里插入图片描述
如果你觉得文章不错,记得点赞+分享喔~如果有地方不对,欢迎随时评论指出 ~


本文转载自: https://blog.csdn.net/Original0/article/details/125112960
版权归原作者 Origin! 所有, 如有侵权,请联系我们删除。

“【C语言进阶】&mdash;&mdash;指针进阶[Ⅰ]”的评论:

还没有评论