指针
前言
相关概念:
- 地址:在arm架构的计算机中,地址是一块连续的空间。地址中的每一个字节都有一个编号,这个编号就称之为地址。
- 指针:指针是一个数据类型
- 指针变量:本质是一个变量,变量里面存地址。
在后续学习中,工作中,以上三个概念统称为 指针 。
指针变量的定义格式:
格式:
<数据类型> *指针名 = value;
| | | |-------->地址
| | |---------------->变量名:符合变量的命名规则
| |-------------------->*是一个指针的标识
|------------------------->指针的类型
eg:
int number = 10;
int *p = &number;//定义一个变量p,变量p里面存放的内容是number的地址;
//指针p里面存放的是number的地址,称之为 p指向number
与指针相关的运算符
& 运算符 :取地址运算符,(获取的是变量的地址),注意: & 是不可以获取常量的地址的。
对于多字节变量,取地址运算符,取得是首地址,标号最小的那个值。
eg:
#include <stdio.h>
int main(int argc, const char *argv[])
{
//定义一个指针,指针执行一个int的地址
//int *p = %10;//10是一个int类型的常量,error
//& 运算符只能获取变量的地址
//定义一个变量number
int number = 10;
printf("&number = %p\n",&number);
return 0;
}
*取值运算符:获取地址所指向空间的使用权; *指针;
左值:等号左边的值,叫做左值;
*指针 = value; 获取指针所指向的空间,并且将右值value赋值到这个空间。
右值:等号右边的值,叫做右值;
*指针; 没有 = 的时候默认为右值;
*指针; 获取指针空间里的值。
简单记忆:
*指针 与 变量名 是等价的。
课堂代码:
#include <stdio.h>
int main(int argc, const char *argv[])
{
//定义一个char类型的变量
char ch = 'a';//在内存中申请一个变量 变量里面存放‘a’
//定义一个变量,用来存放ch的地址
char *p = &ch; //*是不是运算符?
//这里的*表示的不是运算符
//只代表了定义一个char* 类型的指针变量。
//*运算符:
*p = 'A';//*运算符:*p是左值,获取指针p所指向的空间
//并将右值赋值给这个空间
printf("ch = %c,*p = %c\n",ch,*p);//*p是没有=的,所以默认为右值
//*p 获取指针指向空间里面的值
return 0;
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
//1.定义一个 int 类型的变量,名为a
int a = 10; // 操作系统会根据变量的类型给变量分配空间
//2.通过变量名对这块空间进行修改
a = 20;
//3.查看操作系统分配空间,分配到了那里?
printf("&a = %p\n",&a);// 获取 a 的地址;
//4.将a的地址保存到变量中
int *p1 = &a;//定义一个变量p1,p1里面保存变量 a 的地址。
printf("p1 = %p\n",p1);
//5.地址是一个数字,指针又是保存这个地址的变量
int *p2 = 0x1234; //waring:指针只能保存系统分配了的地址
//*p2 = 200; //error:使用了未分配的地址
printf("p2 = %p\n",p2);
//6.地址是一个数字,能否使用变量来保存这个地址
long value = &a;//可以保存但是有警告
//*value = 20;error:可以保存,但是不能进行*取值操作
//7.指针变量的申请:
int b,c;//定义了两个变量b,c,b与c的类型都是 int 类型;
int *pa,pb;//定义了两个变量pa,pb, pa的类型是指针,pb的类型是int类型的变量
int *pc,*pd;//定义了两个指针 pc,pd
return 0;
}
结果:
&a = 0x7ffcc80bdeac
p1 = 0x7ffcc80bdeac
p2 = 0x1234
指针的基本使用
#include <stdio.h>
void swap1(int x,int y)
{
int ret = x;
x = y;
y = ret;
}
void swap2(int *x,int *y)
{
int *ret = x;
x = y;
y = ret;
}
void swap3(int *x,int *y)
{
int ret = *x;
*x = *y;
*y = ret;
}
void swap4(int *x,int *y)
{
int *ret;
*ret = *x;
*x = *y;
*y = *ret;
}
void swap5(int *x,int *y)
{
//改进swap4
int value;//在内存中申请一块变量
int *ret = &value;
*ret = *x;
*x = *y;
*y = *ret;
}
int main(int argc, const char *argv[])
{
int x = 5;
int y = 10;
printf("未调用之前:x = %d,y = %d\n",x,y);
swap5(&x,&y);
printf("调用函数之后:x = %d,y = %d\n",x,y);
return 0;
}
野指针与空指针
野指针
指向一块未确定的区域。
(1)int *p; //指针没有赋初值,p执行的地址:随机的空间
(2)int number = 10;
int *p;
p = &number; //不是野指针:指针p指向的空间是number
野指针的危害:
(1)报错:野指针有可能会造成 段错误 ,代码不能正常运行。
(2)不报错:未知错误;
#include <stdio.h>
int main(int argc, const char *argv[])
{
//*p就是一个野指针
int *p;
*p = 200; //向一个未知区域赋值
//假设不报错的情况
int array[10] = {1,2,3,4,5,6,7,8,9,10};
//target: 打印数组里面的值
int *q;//野指针 q里面刚好就是array[4]的地址
*q = 200;
//将array[4] = 200;
return 0;
}
空指针
在指针定义的时候,不知道指针用哪个地址初始化,可以先将指针指向NULL;
指向NULL的指针,就称之为空指针;
eg:
int *p = NULL; //
// NULL 就是 0 地址;0 地址是不允许用户操作的。
* 或 & 运算符进行运算的时候,会立马报错。
作用:
使用空指针,可以在一定程度上避免野指针的错误。
指针占内存的大小
32位计算机中,无论是什么类型的指针,全部在内存中占 4 字节。
64位计算机中,无论是什么类型的指针,全部在内存中占 8 字节。
#include <stdio.h>
int main(int argc, const char *argv[])
{
char *p1 = NULL;
short *p2 = NULL;
int *p3 = NULL;
long *p4 = NULL;
long long *p5 = NULL;
float *p6 = NULL;
double *p7 = NULL;
printf("sizeof(char *) = %ld, sizeof(p1) = %ld\n",sizeof(char *),sizeof(p1));
printf("sizeof(short *) = %ld, sizeof(p2) = %ld\n",sizeof(short *),sizeof(p2));
printf("sizeof(int *) = %ld, sizeof(p3) = %ld\n",sizeof(int *),sizeof(p3));
printf("sizeof(long *) = %ld, sizeof(p4) = %ld\n",sizeof(long *),sizeof(p4));
printf("sizeof(long long *) = %ld, sizeof(p5) = %ld\n",sizeof(long long *),sizeof(p5));
printf("sizeof(float *) = %ld, sizeof(p6) = %ld\n",sizeof(float *),sizeof(p6));
printf("sizeof(double *) = %ld, sizeof(p7) = %ld\n",sizeof(double *),sizeof(p7));
return 0;
}
结果:
sizeof(char *) = 8, sizeof(p1) = 8
sizeof(short *) = 8, sizeof(p2) = 8
sizeof(int *) = 8, sizeof(p3) = 8
sizeof(long *) = 8, sizeof(p4) = 8
sizeof(long long *) = 8, sizeof(p5) = 8
sizeof(float *) = 8, sizeof(p6) = 8
sizeof(double *) = 8, sizeof(p7) = 8
指针类型的作用
在C语言中:
数据类型的作用在于:表示在内存中申请指定大小的空间。
指针在内存中申请:4 /8个字节。
指针的作用
<1>通过 *(取地址运算符运算的时候) 向后取几个字节的空间 (4或8个字节)
int a = 10; //假设 a
int *p = &a;
编写程序:判断自己的电脑是大端还是小端。
#include <stdio.h>
int main(int argc, const char *argv[])
{
unsigned int number = 0x12345678;
int *p = &number;
if(*((char*)p) == 0x12)
{
printf("计算机是大端机\n");
}
else if((*(char*)p) == 0x78)
{
printf("计算机是小端机\n");
}
else
{
//保证语法的完整性
}
return 0;
}
结果:
计算机是小端机
指针运算
指针里面存放的都是地址编号;指针里面的运算,就是地址的运算。
指针的运算:在连续空间中才有意义。
指针支持的运算符:
算数运算符:+ - ++ --
关系运算符:> < == !=
赋值运算符: =
算术运算符
#include <stdio.h>
int main(int argc, const char *argv[])
{
//1.定义3个变量 分别是char short int
char v1 = 'a';
short v2 = 100;
int v3 = 200;
//2.定义3个不同类型的指针
char *p1 = &v1;
short *p2 = &v2;
int *p3 = &v3;
//3.指针做加法运算:指针+数字
printf("p1 = %p , P1 + 1 = %p\n",p1,p1+1);
printf("p2 = %p , P2 + 1 = %p\n",p2,p2+1);
printf("p3 = %p , P3 + 1 = %p\n",p3,p1+1);
/* 总结:指针类型第二个作用:指针+1 移动其指向类型大小的字节*/
puts("------------------------------------------");
//4.指针做减法运算:指针-数字
printf("p1 = %p , P1 - 1 = %p\n",p1,p1-1);
printf("p2 = %p , P2 - 1 = %p\n",p2,p2-1);
printf("p3 = %p , P3 - 1 = %p\n",p3,p1-1);
puts("------------------------------------------");
//5.指针 - 指针。只有在连续空间中才有意义
int arr[5] = {1,2,3,4,5};
//获取数组里面每一个元素的地址
for(int i = 0;i < 5;i++)
{
printf("arr[%d] = %p\n",i,&arr[i]);
}
printf("&arr[4] - &arr[0] = %ld\n",&arr[4]-&arr[0]);
return 0;
}
结果:
p1 = 0x7ffe5f9c7fad , P1 + 1 = 0x7ffe5f9c7fae
p2 = 0x7ffe5f9c7fae , P2 + 1 = 0x7ffe5f9c7fb0
p3 = 0x7ffe5f9c7fb0 , P3 + 1 = 0x7ffe5f9c7fae
------------------------------------------
p1 = 0x7ffe5f9c7fad , P1 - 1 = 0x7ffe5f9c7fac
p2 = 0x7ffe5f9c7fae , P2 - 1 = 0x7ffe5f9c7fac
p3 = 0x7ffe5f9c7fb0 , P3 - 1 = 0x7ffe5f9c7fac
------------------------------------------
arr[0] = 0x7ffe5f9c7fd0
arr[1] = 0x7ffe5f9c7fd4
arr[2] = 0x7ffe5f9c7fd8
arr[3] = 0x7ffe5f9c7fdc
arr[4] = 0x7ffe5f9c7fe0
&arr[4] - &arr[0] = 4
比较运算符
指针的比较运算符:> < != ==
注意:
指针的 > < : 只有在连续的空间才有意义;
两个普通类型变量的地址之间没有大小关系(因为是操作系统随机分配的);
指针 == 运算符;
表示的是两个变量是否是同一个。
赋值运算
指针赋值运算
本质:给指针赋值操作;
eg:
int number = 10;
int value = 20;
//定义一个指针
int *p = &number;//定义一个指针,里面初始化的值是number的地址
//赋值运算符可以改变指针的指向
p = &value; //将指针的指向 改为指向 value 的地址