【C/C++】指针

本文详细阐述了C语言中指针的概念,包括指针的基本定义、类型、指向的类型及值等内容。并通过具体实例讲解了指针的算术运算、与数组及结构体的关系等高级用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【写在前面】
网上资料梳理,侵删烦请联系。或有表达错误,欢迎指出纠正。
【参考引用】
https://blog.youkuaiyun.com/liu100m/article/details/90731422

指针说明

int p;
//普通整型变量
int p;
//p与
结合,p是一个指针;*p再与int结合,指针指向的内容的类型为int。p是一个返回整型数据的指针。
int p[3];
//p与[]结合,p是一个数组;p[]再与int结合,数组里的元素是整型的。p是由整型数据组成的数组。
int p[3];
//p与[]结合,p是一个数组;p[]再与
结合,数组里的元素是指针类型;再与int结合,指针指向内容的类型是整型。p是一个由返回整型数据的指针组成的数组。
int (p)[3];
//p与
结合,p是一个指针;*p再与[]结合,指针指向内容为数组;再与int结合,数组里的元素是整型。p是一个指向由整型数据组成的数组的指针。

int **p;
//p与*结合,p是一个指针;p再与结合,指针所指向的元素是指针;再与int结合,指针指向内容的类型是整型。p是二级指针。
int p(int);
//p与()结合,p是一个函数;p()内参数为int,函数有一个整型变量参数;再与int结合,函数返回值是一个整型数据。
int (p)(int);
//p与
结合,p是一个指针;*p再与()结合,指针指向内容是一个函数;(*p)()内参数为int,函数有一个整型变量参数;再与int结合,函数返回值是一个整型数据。p是一个指向有一个整型变量、返回类型为整型的函数的指针。

细说指针

指针是一个特殊的变量,里面存储的数值是内存里的一个地址。
理解:指针的类型、指针指向的类型、指针的值/指针指向的内存区间、指针本身所占据的内存区域。
注注注:每遇到一个指针,明确:指针的类型是什么?指针指向的类型是什么?指针指向了哪里?
示例:
(1)intptr;
(2)char
ptr;
(3)int**ptr;
(4)int(ptr)[3];
(5)int
(*ptr)[4];

指针的类型

指针本身所具有的类型。(将指针声明语句里的指针名字去掉,剩下部分即为指针的类型)(去掉ptr)
(1)int*
(2)char*
(3)int**
(4)int()[3]
(5)int
(*)[4]

指针指向的类型

将指针声明语句中的指针名字、名字左边的指针声明符去掉,剩下部分即为指针指向的类型(去掉ptr)。
通过指针访问指针指向的内存区域时,指针所指向的类型决定编译器将内存区域的内容当作什么看待。
(1)int
(2)char
(3)int*
(4)int[3]
(5)int*[4]

指针的值

指针指向的内存区域或地址。
指针的值是指本身存储的数值,该值被编译器当作一个地址,而不是一般的数值。
在32位程序里,所有类型的指针的值都是一个32位整数。(32位程序中,内存地址均长为32)
指针指向的内存区域:从指针的值所代表的内存地址开始,长度为sizeof(指针指向的类型)的内存区域内。指针的值是xx,说明指针指向了以xx为首地址的内存区域。指针未初始化时,其指向的内存区域不存在,或者无意义。

指针本身所占据的内存区域

指针本身占据多大内存,使用sizeof(指针类型)测试。
在32位平台,指针本身占据4个字节长度。可用于判断一个指针表达式是否为左值。

指针的算术运算

指针的加减运算以单元为单位。
char a[20];
int ptr = (int)a; //强制类型转换不会改变a的类型
ptr++;
ptr类型是int*,被初始化为指向整型变量a
指针ptr+1,即把指针ptr的值加上sizeof(int)。在32位程序中,加上4(int所占字节);ptr指向的地址由原来的变量a的地址向高地址方向增加4个字节。

int array[20] = {0};
int *ptr = array;
for(i=0; i<20; i++)
{
(*ptr)++; //将a[0]中的各个值+1
ptr++; //将a[0]+1,进入下一个单元a[1]
}
//用1个指针和1个循环来遍历1个数组。

char a[20]=“You_are_a_girl”;
int ptr=(int )a;
ptr+=5; //将指针ptr的值+5
sizeof(int),在32位程序中即加上5
4=20。地址的单位是字节,故ptr所指向的地址向高地址方向移动了20个字节。
没加5前的ptr指向数组a的第0号单元开始的四个字节,加5后,ptr指向数组a的合法范围之外。虽然这种情况在应用上会出问题,但在语法上可行。

char a[20]=“You_are_a_girl”;
char p = a;
char **ptr = &p;
printf("**ptr=%c\n",**ptr);
ptr++;
printf("**ptr=%c\n",ptr);
ptr类型是char
,指向类型为char
类型,指向的地址是p的地址(&p);
执行ptr++时,会使指针加一个sizeof(char*),即&p+4;*(&p+4)指向值不确定。
总结:
(1)一个指针ptrold加(减)一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold 的值增加(减少)了n乘sizeof(ptrold 所指向的类型)个字节。
(2)指针加法运算:两个指针不能进行加法运算,是非法操作,因为进行加法后,得到的结果指向一个不知所向的地方,而且毫无意义。
(3)指针减法运算:两个指针可以进行减法操作,但必须类型相同,一般用在数组方面。

运算符&和*

&—取地址运算符;—间接运算符
&a的运算结果是一个指针,指针类型为a的类型加个
,指针指向类型为a的类型,指针指向地址为a的地址。
*p的运算结果是p所指向的东西,该东西特点:类型为p指向的类型,占用地址为p指向的地址。

指针表达式

运算结果为指针的表达式。
具备指针四要素:指针的类型,指针所指向的类型,指针指向的内存区,指针自身占据的内存。
int a,b,array[10],*pa;
pa = &a; //&a是一个指针表达式
int **ptr = &pa; //&pa是一个指针表达式
*ptr = &b; //*ptr与&b均为指针表达式
pa = array;
pa++; //指针表达式

数组与指针

数组的数组名可以看作一个指针。
int array[10] = {0,1,2,3,4,5,6,7,8,9},value;
value = array[0]; //可以写成:value = *array;
value = array[3]; //可以写成:value = (array+3);
数组名array代表数组本身,类型为int[10];
将array看作指针,指向数组的第0个单元,类型是int
,指向的类型是数组单元的类型,即int。
array+3是一个指向数组第3个单元的指针。

char str[3]={
“Hello,thisisasample!”,
“Hi,goodmorning.”,
“Helloworld”
};
char s[80];
strcpy(s,str[0]); //也可写成strcpy(s,str);
strcpy(s,str[1]); //也可写成strcpy(s,
(str+1));
strcpy(s,str[2]); //也可写成strcpy(s,
(str+2));
str是一个三单元的数组,该数组的每个单元都是一个指针,这些指针各指向一个字符串。
把指针数组名str当作一个指针,它指向数组的第0号单元,它的类型是char **,它指向的类型是char
str也是一个指针,它的类型是char ,它所指向的类型是char,它指向的地址是字符串"Hello,thisisasample!"的第一个字符的地址,即’H’的地址。
注:字符串相当于一个数组,在内存中以数组的形式储存,只不过字符串是一个数组常量,内容不可改变,且只能是右值.如果看成指针,他即是常量指针,也是指针常量.
str+1是一个指针,它指向数组的第1号单元,它的类型是char
,它指向的类型是char

(str+1)也是一个指针,它的类型是char,它所指向的类型是char,它指向"Hi,goodmorning."的第一个字符’H’。

数组的数组名(数组中储存的也是数组)
(1)声明了一个数组TYPE array[n],则数组名称array有了两重含义:
第一,它代表整个数组,它的类型是TYPE[n];
第二,它是一个常量指针,该指针的类型是TYPE*,该指针指向的类型是TYPE,也就是数组单元的类型,该指针指向的内存区就是数组第0号单元,该指针自己占有单独的内存区,它和数组第0号单元占据的内存区是不同的。该指针的值是不能修改的,即类似array++的表达式是错误的。
(2)在不同的表达式中数组名array可以扮演不同的角色:
在表达式sizeof(array)中,数组名array代表数组本身,故sizeof函数测出的是整个数组的大小。
在表达式*array中,array扮演的是指针,表达式的结果就是数组第0号单元的值。sizeof(*array)测出的是数组单元的大小。
表达式array+n(其中n=0,1,2,…)中,array 扮演的是指针,故array+n的结果是一个指针,它的类型是TYPE *,它指向的类型是TYPE,它指向数组第n号单元。故sizeof(array+n)测出的是指针类型的大小。在32位程序中结果是4。

sizeof(对象)测出的都是对象自身类型的大小。

指针与结构类型的关系

可以声明一个指向结构类型对象的指针。
struct MyStruct
{
int a,b,c;
};
struct MyStruct ss={20,30,40}; //声明了结构对象ss,并把ss的成员初始化为20,30 和40。
struct MyStruct *ptr=&ss; //声明了一个指向结构对象ss的指针。它的类型是MyStruct *,它指向的类型是MyStruct。
int pstr=(int)&ss; //声明了一个指向结构对象ss的指针。但是pstr和它被指向的类型ptr是不同的。
通过指针ptr访问ss的成员变量:
ptr->a; //指向运算符
通过指针pstr访问ss的成员变量(不正规):
*pstr; //访问ss的成员a
*(pstr+1); //访问ss的成员b
*(pstr+2); //访问ss的成员c

int array[3]={35,56,37};
int *pa=array;
//通过指针pa访问数组array的三个单元的方法:
*pa; //访问了第0号单元
*(pa+1); //访问了第1号单元
*(pa+2); //访问了第2号单元

指针访问数组/指针访问结构对象成员
C/C++编译器在排列数组的单元时,总是把各个数组单元存放在连续的存储区里,单元和单元之间没有空隙。
在存放结构对象的各个成员时,在某种编译环境下,可能会需要字对齐等,需要在相邻两个成员之间加若干个"填充字节",导致各个成员之间可能会有若干个字节的空隙。
因此,即使pstr访问到了结构对象ss的第一个成员变量a,也不能保证(pstr+1)就一定能访问到结构成员b。

指针与函数的关系

可以将一个指针声明成为一个指向函数的指针。

指针类型转换

指针的安全问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值