指针学习笔记
一、认识指针
1. 指针的基本概念
- 指针即内存地址,也被称为指针变量,大小为4个字节(或8个字节)的变量。
- 指针变量是用来存放内存地址的变量。
- 通过指针,能够对该指针指向的内存区域进行读写。
- 如果把内存的每个字节都想象成宾馆的一个房间,那么内存地址相当于就行房间号,而指针里存放的,就是房间号。1
2
2. 指针的定义
类型名 *指针变量名 T *p
T可以是任何类型的名字,比如int
,double
*p
等价于存放在地址p处的一个T类型的变量
*
间接引用运算符
ps: 通过表达式*p
,可以读写从地址p开始的sizeof(T)
个字节
int *p;//p是一个指针,变量p的类型是 int *
char *pc;//pc是一个指针,变量pc的类型是 char *
float *pf;//pf是一个指针,变量pf的类型是 float *
3. 指针的用法
char ch1 = 'A';
char *pc = &ch1;//使得pc指向变量ch1
&
: 取地址运算符
&x
: 变量x的地址(即指向x的指针)
对于类型为T的变量x, &x
表示变量x的地址(即指向x的指针)
&x
的类型是 T *
。
#include<stdio.h>
int main()
{
int a;
int *p = &a;
scanf("%d",&a);
printf("a = %d\n",a);
scanf("%d",p);
printf("a = %d\n",a);
return 0;
}
4. 指针的作用
有了指针,就有了自由访问内存空间的手段
- 不需要通过变量,就能对内存直接进行操作。通过指针,程序能访问的内存区域就不仅限于变量所占据的数据区域
- 在C++中,用指针p指向a的地址,然后对p进行加减操作,p就能指向a后面或前面的内存区域,通过p也就能访问这些内存区域
ps: 不同类型的指针,如果不经过强制类型转换,不能直接互相赋值
ps: 常见显示地址的方法
#include <stdio.h>
int main(){
int a = 100;
char str[20] = "KeproZ";
printf("%#X, %#X\n", &a, str);
return 0;
}
#include<stdio.h>
int main()
{
char str[128];
printf("请输入英文单词:");
scanf("%s",str);
printf("英文单词的地址是:%p\n",str);
return 0;
}
二、指针的运算
1. 指针基本运算
- 两个同类型的的指针变量,可以比较大小
- 两个同类型的的指针变量,可以相减
p 1 − p 2 = ( 地址 p 1 − 地址 p 2 ) / s i z e o f ( T ) p1 - p2 = (地址p1 - 地址p2) / sizeof(T) p1−p2=(地址p1−地址p2)/sizeof(T) - 指针变量加减一个整数的结果是指针
p+n
指向地址:地址p + n * sizeof(T)
- 指针变量可以自增、自减
p++
++p
: p指向n + sizeof(T)
p--
--p
: p指向n - sizeof(T)
- 指针可以用下标运算符
[]
进行运算
p[n]
等价于*(p+n)
2. 示例
#include<stdio.h>
int main()
{
int *p1,*p2;
int n = 4;
char *pc1,*pc2;
p1 = (int *)100;
p2 = (int *)200;
printf("%d\n",p2 - p1);//输出25,因为(200-100)/sizeof(int)=25
pc1 = (char *)p1;
pc2 = (char *)p2;
printf("%d\n",pc1 - pc2);//输出-100,因为(100-200)/sizeof(char)=-100
printf("%d\n",(p2 + n) - p1);
int *p3 = p2 + n;//p2+n是一个指针,可以用它给p3赋值
printf("%d\n",p3 - p1);
printf("%d\n",(pc2 - 10) - pc1);
return 0;
}
三、空指针
- 地址0不能访问,指向地址0的指针就是空指针
- 可以用“NULL”关键字对任何类型的指针进行赋值。NULL实际上就是整数0,值为NULL的指针就是空指针:
int *pn = NULL;
char *pc = NULL;
int *p2 = 0;
- 指针可以作为条件表达式使用。如果指针的值为NULL,则相当于为假,值不为NULL,就相当于为真
i f ( p ) < = = > i f ( p ! = N U L L ) if (p) <==> if(p!=NULL) if(p)<==>if(p!=NULL)
i f ( ! p ) < = = > i f ( p = N U L L ) if (!p) <==> if(p=NULL) if(!p)<==>if(p=NULL)
四、指针作为函数参数
C语言允许函数的返回值是一个指针(地址),我们将这样的函数称为指针函数。
#include<stdio.h>
void Swap(int *p1,int *p2)
{
int tmp = *p1; //将p1指向的变量的值,赋给tmp
*p1 = *p2; //将p2指向的变量的值,赋给p1指向的变量
*p2 = tmp; //将tmp的值赋给p2指向的变量。
}
int main()
{
int m = 3,n = 4;
Swap(&m,&n); //使得p1指向m,p2指向n
printf("%d %d",m,n); //输出4,3
return 0;
}
- 指针对四个整数进行排序
#include<stdio.h>
void psort(int *pa,int *pb,int *pc,int *pd)
{
int a[5],i,j,t;
a[1]=*pa;a[2]=*pb;a[3]=*pc;a[4]=*pd;
for(i=1;i<=3;i++)
{
for(j=1;j<=4-i;j++)
{
if(a[j]<a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
*pa=a[1];*pb=a[2];*pc=a[3];*pd=a[4];
}
int main()
{
void psort(int *pa,int *pb,int *pc,int *pd);
int a,b,c,d;
int *p1,*p2,*p3,*p4;
scanf("%d %d %d %d",&a,&b,&c,&d);
p1=&a;p2=&b;p3=&c;p4=&d;
psort(p1,p2,p3,p4);
printf("%d %d %d %d",a,b,c,d);
return 0;
}
五、指针和数组
1. 指针和数组的关系
- 数组的名字是一个指针常量,指向数组的起始位置
T a[N];
- a的类型是T *
- 可以用a给一个T * 类型的指针赋值
- a是编译时其值就确定了的常量,不能够对a进行赋值
- 作为函数形参时。
T *p
和T p[]
等价
void Func(int *p){ printf("%d",sizeof(p)); }
/\
||
\/
void Func(int p[]){ printf("%d",sizeof(p)); }
2. 示例
- 指针的应用
#include<stdio.h>
int main()
{
int a[200];
int *p;
p = a; //p指向数组a的起始地址,亦即p指向了a[0]
*p = 10; //使得a[0]=10
*(p + 1) = 20; //使得a[1]=20
p[0] = 30; // p[i]和*(p+i)是等效的,使得a[0]=30
p[4] = 40; //使得a[4]=40
for(int i=0;i<10;++i) //对数组a的前10个元素进行赋值
*(p + i) = i;
++p; //p指向a[1]
printf("%d\n",p[0]); //输出1,p[0]等效于*p,p[0]即是a[1]
p = a + 6; //p指向a[6]
printf("%d\n",*p); //输出6
return 0;
}
- 颠倒数组
#include<stdio.h>
void Reverse(int *p,int size) //颠倒一个数组
{
for(int i=0;i<size/2;++i)
{
int tmp = p[i];
p[i] = p[size-1-i];
p[size-1-i] = tmp;
}
}
int main()
{
int a[5] = {1,2,3,4,5};
Reverse(a,sizeof(a)/sizeof(int));
for(int i=0;i<5;++i)
printf("%d,",*(a+i)); //输出5,4,3,2,1,
return 0;
}