指针定义
指针即地址,
int* p=&a;
我们用指针变量p保存a的地址,形象的称为p指向a。
指针有两个值:自身的值p,指向的值*p。(或者说还有一个值 &p,自己的地址,用二级指针**q保存)
定义时将 int * 写在一块,便于区分和理解。
int *;自身类型
int ;指向类型
#include<stdio.h>
int main()
{
int a = 10;
int* p = &a;//p指向a
int * q = p;//q也指向a,把p存的值给了q,p保存的是a的地址
int * w = &p;//“初始化”:“int *”与“int **”的间接级别不同
//C语言在此不会报错,C语言类型检查不严格,若文件为cpp则会报错,类型不匹配
return 0;
}
通过指针交换变量的值
#include<stdio.h>
void swap(int* a, int* b)//形参a,b指向了实参变量,通过指针解引用赋值修改,达到对实参变量的交换
{
int temp = *a;
*a = *b;
*b = temp;
}
/*
错误写法:
int* temp=a;
a=b;
b=temp;
这是将a,b实参的地址交换 v
*/
int main()
{
int a = 10;
int b = 20;
printf("a=%d b=%d\n", a, b);
swap(&a, &b);
printf("a=%d b=%d\n", a, b);
return 0;
}
指针变量所占字节数都是4,不论是什么类型的指针。(32位操作系统下,64位下为8个字节)
因为指针变量要保存的是地址,32位下地址0~2^32,申请的地址是任意的,要能对所有产生的地址都能保存所以需要四个字节,一个字节八位。
指针的类型决定了解引用时访问的字节数,以及对指针加一时增加的字节数,类型决定步长。
指针操作
指针可以进行那些操作:
赋值:把地址赋给指针
解引用:*获得指向地址上存储的值
取址(三声):获取自己的地址
和整数相加减:+n会增加(n *sizeof(type))字节
自增自减
相减:指针减指针(不能指针加指针)
比较:可以比较,充当循环结束条件。
#include<stdio.h>
#include<assert.h>
int main()
{
char* str = NULL;
assert(str != NULL);//断言 判断 debug时才有用
return 0;
}
/*
int main()
{
float values[5];
float* vp;
for (vp = &values[0]; vp < &values[5];)//指针之间可以通过比较关系来达到条件约束
*vp++ = 0;
return 0;
}
*/
指针常量与常量指针
int main()
{
int a = 10;
int b = 20;
const int* p = &a;//看const修饰的是p还是*p
/*
const int *p//封锁*p,即封锁指向的值,不能通过指向改变值的内容,即不能通过*p 修改a
int * const p//const 封锁p的值不能修改 不可以p=&a,封锁指向
const int * const p
*/
p = &b;
//*p = 100;
return 0;
}
指针数组,数组指针
指针数组,是一个数组,存的元素时指针。int* brr[3]={&1,&b,&c}; 元素类型为int*
数组指针,是一个指针,指向一个数组。int (*brr)[3];brr指向一个int型数组
野指针
#include<stdio.h>
int* test();
int main()
{
//int a = 10;//在内存中开辟一块空间
//&a;//a的地址
//int* p = &a;//用指针变量保存a的地址,sizeof(p)= 4,(64位操作系统为8)
printf("%d\n", sizeof(char*));
printf("%d\n", sizeof(short*));
printf("%d\n", sizeof(int*));
printf("%d\n", sizeof(double*));
/*都是4*/
int a = 0x11223344;
int* pa = &a;
//*pa = 0;//通过地址pa访问a的内容
char* pc = &a;//这里赋值是没有问题的
*pc = 0;//这里只会修改一个字节的内容 Ox11223300
/*
指针类型决定了指针进行解引用时,能够访问的空间大小
int* 4个字节
char* 1个字节
double* 8个字节
*/
/*指针类型决定了指针的步长*/
printf("%p\n", pa);//0072FE54
printf("%p\n", pa + 1);//0072FE58 +1跳过四个字节,步长4
printf("%p\n", pc);//0072FE54
printf("%p\n", pc + 1);//0072FE55
int arr[10] = { 0 };
int* p = arr;//数组名——首元素地址
for (int i = 0; i < 10; ++i)
{
*(p + i) = 1;
}
for (int i = 0; i < 10; ++i)
printf("%d ", *(p + i));
printf("\n");
int size = (p+1)-p;
char* p2 = arr;
for (int i = 0; i < 10; ++i)
{
*(p2 + i) = 0;//0 0 0 1 1 1 1 1 1 1只改了前三位,因为这里按逐个字节修改,总共改10个字节,int3个有12位,因为这里是1,所以对于第三个数的前两位修改就会使1变0
}
for (int i = 0; i < 10; ++i)
printf("%d ", *(p + i));
printf("\n");
//int* p3;//野指针:指向位置不可知(随机,错误,无限制)
//*p3 = 20;//不知会把那个内存位置的值修改了
//没有初始化和数组越界访问都会造成野指针
int* p4 = test();/*指针指向已经释放的内存*/
*p = 20;
return 0;
}
int* test()
{
int a = 10;//函数执行完毕a的内存就会被释放,所以下面返回的内存已被释放
return &a;
}
使用指针常用来传参,得到返回值,return只能返回一个值,使用指针可以再函数中操作实参,修改实参。对数组操作只能传指针,但有时不想数组被修改,只读权限,可以再传参时加const
int sum(const int* a,int n)
这里可以通过常量指针来理解,const封锁*p,即不可以通过指针来修改它所指向的值
不能把const数组的地址给普通指针