新网创想网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
指针入门,这一篇文章应该就够了。如有错误或不足,还望多多指正。
创新互联拥有10多年成都网站建设工作经验,为各大企业提供网站设计、网站制作服务,对于网页设计、PC网站建设(电脑版网站建设)、app软件开发、wap网站建设(手机版网站建设)、程序开发、网站优化(SEO优化)、微网站、申请域名等,凭借多年来在互联网的打拼,我们在互联网网站建设行业积累了很多网站制作、网站设计、网络营销经验,集策划、开发、设计、营销、管理等网站化运作于一体,具备承接各种规模类型的网站建设项目的能力。文章目录地址
:这里以int类型为例,
因为一个int类型4个字节Byte(32位和64位机器中)
所以可以简单理解为这个int占了四个绿色小方框。
那么此时,这个int变量的地址就是1000,即第一个绿色小方框右边的数字。
即就是:这个绿色方框在内存中所处的位置。
指针
:还是这个例子
那
指针
就是一个变量
,比如这个变量名就叫p
吧。
那这个p是个啥东西呢?
把这个1000存到p里去,即,把int类型变量a的地址存进新的变量p中。
那么p这个变量就是一个指向a的指针。
1.3 为什么要使用指针这个东西呢通俗理解下就是:
小明是个舔狗,喜欢小a,但是他比较害羞,不敢直接找小a。
所以小明就找到了小p。为什么找小p呢,因为小p有小a家的地址。
这样小明就可以把给小a送的东西放小a家门口了。这里的小a和小p就相当于例子中的int类型的a变量和指向a的指针p。
我只要找到了p就相当于找到了a
首先我们要明白一直知识点:
需要说明一下的是指针类型存储的是所指向变量的地址:
所以32位机器只需要32bit,而64位机器需要 64bit
由此可知,在一台电脑上,所有指针大小都是一样的。
那么,当我们定义了一些非常复杂庞大的结构体,比如这个结构体有50个字节(Byte)。
这时候,向函数中传入参数的时候,是直接把这个50个字节的数据的副本传递到形参上快?
还是,直接传递32bit或者64bit的指针快呢??
很明显,传入指针可以大大大大提高运算的效率。
1.4 指针变量的定义刚才说了,指针变量是来保存别的变量地址的一种变量。那该如何定义呢?
如何让计算机一眼认出来这一串数字是地址,而不是普通的数字呢?
基本格式:基本类型 *指针变量名 = &变量名;
(也可以先省略=后面的内容,先只定义,不赋值,但是还是建议定义的时候就进行赋值)
//定义变量:
int a = 666;
char b = 'b';
//定义指针变量:
//1.告诉计算机这是一个保存int类型数据地址的指针变量
int *pa = &a;
//2.告诉计算机这是一个保存char字符类型数据地址的指针变量
char *pb= &b;
上面的代码,我定义了两个指针变量,一个是p
一个是p2
。
看见了两个奇怪的符号*
和&
*
这个符号,为取值运算符
啥是取值运算符呢?
就是,我现在有了指针,指针里存的是一个变量的地址,
我现在要通过地址取到这个变量的值。注意:指针里存的是地址,就是通过这个地址找到这个地址住的谁。
举例
比如上面的代码中,pa这个变量存的是a的地址,变量a中存的是666。
那么*pa就可以相当于666。
所以可以明确一点。取值运算符会和指针变量连用。
为啥呢?
因为我们要通过地址取地址所指向的变量中存放的值呀!
1.4.2如果还不明白没关系,在说完&后我对上面的代码解释说明一下。
&
这个符号,为取地址运算符
这个就很简单了。一个int变量名叫a存的是666
我给a前面加上&,变成&a
那么这个&a
就不是666啦。而是,存666的那个内存的地址。
所以我们又可以明确一点。取地址运算符会和一般变量(非指针变量)连用。
为啥呢?
因为指针变量已经是地址了,一般情况我们不需要取地址的地址,即指针的地址。
我们要的是什么。是普通变量的地址。
所以,下面这个代码可以这么理解:
int a = 666;
int *pa = &a;
1.4.3 定义的关键先定义一个int变量a 里面存着666.
第二行咱们丛后往前看:&a
是取地址,所以说,=
后面就是一个地址。
然后我们理解pa = &a
:
这其实就相当于pa里面存的是变量a的地址。
然后,pa
前面加上*
构成了*pa
*pa
是什么,是把pa地址中存的整型变量a取出来了。
所以*pa
其实就是666,相当于一个整型变量。
然后,最前面是int。int后面的*pa
也可以理解为一个int类型的变量。(这是我本人的一种理解方式,只希望大家能更快理解这个式子,可能底层并不是我这样的,哈哈)
指针与数组分成两个方面:
2.1 指向数组元素的指针 2.1.1 数组元素地址赋值给指针变量一、指向数组元素的指针
二、指针数组(数组元素是指针)
首先我们要知道
数组名,其实就是这个数组下标为0的数组元素的地址。
这个地址也就是这个数组的地址。所以,数组给指针复试和数组元素给指针赋值很不一样。
因为,指针只能存地址。
数组名本身就保存的地址,所以就直接可以给指针变量赋值。
数组的元素保存的就是具体的内容了,可能为int可能为char。
所以,数组元素赋值的时候,就要先用取地址符&得到这个元素的地址,然后再给指针变量赋值。
int c[10], d[20];
int *p, *q=&c[0];
p = &c[3];//数组c下标为3的元素赋值给指针P
p = d;//整个数组的地址赋值给指针p
2.1.2 指针运算众所周知,数组,存在内存中一片地址连续的区域中
即就是说,数组,在逻辑上是一个元素挨着一个元素,在物理存储上也是一个元素挨着一个元素的。
所以,当指针变量指向数组元素时,指针变量加/减一个整数n,表示指针向后/前移动n个元素!
注意,这里+n是移动一个元素,不是移动n个字节
当然,移动几个元素就指针的具体值就增加或减少这个几个元素所占的字节数
比如:int 数组中,指针指向某个元素,然后给这个指针+2
那么这个指针本身的值就应该加几?
一个int元素占4个字节,俩就是8个字节,
那么地址字节值就要加8
看例子:
int c[20];
int *p1 = &c[9];
p1--;
p1+=3;
2.1.2.2 数组元素指针之间加减(注意,只有加减没有乘除)2.1.2.3相减得到的这个数字是这两个地址之间相差的字节数。
然后,用这个字节数,除以每个元素所占的字节数。
就可以得出这两个地址之间相差几个元素。
我们在复习一下:
数组名,就是这个数组的首地址,也是这个数组中下标为0元素的地址。
好了,那如果我们把这个数组的首地址保存在一个指针变量中,然后对这个指针变量直接+或者-
这样是不是就可以遍历数组了呢?
C语言将数组元素中的
[ ]
称为变址运算符
一维数组元素b[j]
的表示形式等价于*(b+j)
(大家不要忘记*
是取值运算符哦,就是把这个地址中存的具体的值取出来)
举例:
int b[20],*p = b;
//数组元素b[j]还有下面两种表示方式
//*(p+j)
//*(b+j)
//p[j] 注意:指针变量也是可以带下标的,但是一般只有在数组上才这么用
**注意:**数组名b是符号常量,所以,不能给b赋值。这个b就类似于函数的名字一样,我们不能随便改变已经定义好的函数的名字。
空指针:
2.2 指针数组C语言设置了一个指针常量NULL,称为空指针。空指针不指向任何存储单元。
空指针可以赋值给任何指针类型的变量。
整形数组中,数组元素都是整型
字符数组中,数组元素都是字符
指针数组中,数组元素都是指针
int i = 1;
int j = 2;
int k = 3;
int l = 4;
int *p[4] = {&i, &j, &k, Kl};
//单目运算符,同优先级的情况下,丛右往左进行运算
//[]先与p结合,表示这是一个数组
//*再与p[]结合,表示这个数组元素类型是指针
//最后加上前面的int,表示这个int类型的指针
注意区分两个概念:
int (*p)[5];
//这里*先与p结合,表示p是一个指针,这个指针指向这个数组,这个数组是int类型的数组
int *p[5];//这个表示指针数组,每个元素都是指针,上面说过了
三、指针与函数
3.1 返回值是指针的函数指针函数:
函数的返回值的类型既可以是整型(若没有设定,则默认为整型),实型,字符型,也可以是指针型。
返回值为指针类型的函数又称为指针类型的函数,建成指针函数。
具体定义格式如下:类型名 *函数名(参数表)
int *a(int x)
//解释一下
//这里函数名先和()结合,表示这是一个函数
//然后a()再和前面的*结合,表示这是一个指针类型的函数。
//最后与前面的int结合,表示这是int指针类型的函数,返回值是指针
//(这个过程有点类似前面的指针数组,可以翻上去复习一下)
3.2 指向函数的指针变量c语言的每个函数的编译的时候,都分配了一段连续的内存空间和一个入口地址,
这个入口地址就称为“指向函数的指针”
,即函数指针
。可以用一个变量来存储函数指针,这个变量就称为
“指向函数的指针变量”
或者函数指针变量。通过
函数指针变量
就可以调用所指向的函数,改变它的值就可以动态调用不同的函数。
一般定义形式类型说明符 (*变量名)()
eg:
int (*p)();
//说明一下:
//p先和*结合(括号的运算优先级高),表明该变量名是指针变量
//然后(*p)后面的括号表示该指针变量指向一个函数
//最前面的int 表明这个函数返回值类型为Int
//这个变量p是专门用来存放整型函数的入口地址的
那如何通过函数指针变量调用函数呢?
那就是让函数指针变量p指向一个具体的函数,即将某个函数的入口地址赋值给这个指针变量。
那一般函数的入口地址在哪里呢?
函数名就代表函数的入口地址,是函数指针类型的符号常量。(这里和数组有点类似,数组名也是数组的地址。)
//ok 比如现在有个函数,函数名叫abc,就可以对函数指针变量p赋值了
p = abc;
那赋值给函数指针变量p以后,如何使用p来调用这个函数呢?
四、指针和结构体 4.1 结构体变量成员的引用还记得我们的取值运算符
*
吗?
本来调用函数应该是这样的函数名();
那现在,函数名的位置用*函数指针变量名
来代替就可以啦
剩下的就和普通函数的使用方式基本一样啦。
typedef struct student{char name[21];
int age;
char sex;
float score;
};
student st1;
//现在给第一个学生的年龄赋值
st1.age = 20;
//普通结构体引用成员的时候使用.
//.前面是定义的结构体变量,.后面是要引用的结构体中的成员
4.2 指针与结构体结构体类型是一种构造类型,与简单类型(int、float和char等)一样,也可以定义为指针变量,定义方法也相同。
typedef struct student{char name[21];
int age;
char sex;
float score;
}student,*stu;
//这里解释一下*stu,就是student类型的指针变量,即这个指针指向一个student结构体
stu q = null;
//这里定义的这个p直接就是一个指针类型的变量,因为stu在typedef语句中就背定义为指针了
student s;
student *p = s;
q = p;
//下面有这几种方法可以访问student的成员age(别的成员访问方式类似)
s.age = 10;
(*p).age = 10;
p->age = 10;
q->age = 10;
**注意:**如果用结构体指针在不加取值运算符*
的情况下想直接访问结构体成员要用到->
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧