C/C++(指针)

c语言指针

所有在内存中的数据结构均可用指针来访问。
认识内存:线性存储

int a[3];//逻辑和存储均为线性
int b[3][4];//二维数组的逻辑是二维的,存储结构是线性的
for(int i = 0;i<3;i++) {
    for(int j = 0;j < 4;j++) {
        printf("%p
",&arr[i][j]);
    }
    putchar(10);//输出的地址是线性的 
}

存储结构是现行的原因是由内存的物理特性决定的,数组在内存中是一段连续的存储空间

变量的地址

&:取地址
除了char占一个地址,其他的类型包含多个字节也就是多个地址,当我们对一个变量取地址时拿到的是低位字节的地址。

char a;short b;int c;double d;
printf("%p
",&a);
printf("%p
",&b);
printf("%p
",&c);
printf("%p
",&d);
//大小问题---32位下4字节,64位机下8字节,地址的大小与类型没有关系,与平台有关系
printf("sizeof(&a) = %d
",sizeof(&a));
printf("sizeof(&b) = %d
",sizeof(&b));
printf("sizeof(&c) = %d
",sizeof(&c));
printf("sizeof(&d) = %d
",sizeof(&d));

对变量取地址,取出的地址就是一个指针,且是常量指针。
&:reference,*:derefer运算互逆。狭义上是取地址和取内容。
常量指针不是一个单纯的地址+而是有类型的。
指针的本质:是一个有类型的地址,类型决定了从这个地址开始的寻址能力。

char a = 1;short b = 2;int c = 3;double d = 121.2345;
printf("&a = %p
",&a);
printf("&b = %p
",&b);
printf("&c = %p
",&c);
printf("&d = %p
",&d);
/*
&a = 0061FEAF
&b = 0061FEAC
&c = 0061FEA8
&d = 0061FEA0
*/

printf("%d
",*(&a));
printf("%d
",*(&b));
printf("%d
",*(&c));
printf("%f
",*(&d));
//互为逆运算
printf("%d
",*((char *)0x0061FEAF));
printf("%d
",*((short *)0x0061FEAC));
printf("%d
",*((int *)0x0061FEA8));
printf("%f
",*((double *)0x0061FEA0));//前面不加类型会报错。
int data = 0x12345678;
printf("%p
,&data");

printf("%x
",*(&data));
printf("%p
",*((int*)));

指针变量

申明一个指针类型变量:要保存两种东西,一个地址数据,而是类型。
type * pointerName
:表明了本变量是指针,4个字节大小,此处只是表示申明(其他地方是的*一般是取内容作用)。type,类型决定了该指针变量中存储的地址的寻址能力。

int data = 0x12345678;
int *pd = &data;
printf("%x
",*(&data));//12345678通过*原始取数据

printf("%x
",*pd);//12345678通过指针的形式直接取内容,无需转换
printf("%x
",*(int*)pd);//12345678
printf("%x
",*(short*)pd);//5678
printf("%x
",*(char*)pd);//78类型表示取地址能力
//对地址不可以赋值

指向/被指向/更改指向

指向:指向谁就是保存了谁的地址。
被指向:
更改指向:指针可以改变。

野指针

指向一段无效的空间,即无效的指针。
有两种形式:

1 未初始化
2 指向已经被释放的空间

int *pa;
*pa = 100;//野指针,未知的空间
//即使不使用申明成NULL指针
int *p = NULL;//(void *) 0,专门初始化未初始化的指针

void

void一个字节,c语言中最小的单位。

printf("sizeof(void) = %d
",sizeof(void));//1
printf("sizeof(char) = %d
",sizeof(char));//1以后还可以扩展

//运算符的重载,由语境决定运算符的属性
int data;
int *p = &data;//*表示申明
*p = 200;//*表示解引用,取内容。

指针的运算

+,-,++,--
指针:类型(步长)+地址(物理数据)
数值+1:简单的加1
指针+1:加的是步长,即指针类型的大小

int *p = (int*)0x0001;
int pData = 0x0001;
printf("p = %d p+1 = %d
",p,p+1);//1,5
printf("pData+1 = %d pData+1 = %d
",pData,pData+1);//1 2

printf("(doouble*)p = %d (double*)p+1 = %d
",(double*)p,(double*)p+1);//1,9
printf("(int*)pData+1 = %d (int*)pData+1 = %d
",(int*)pData,(int*)pData+1);//1 2

int arr[10];
int * pHead = &arr[0];
int * pTail = &arr[9];
printf("%d
",pTail - pHead);//9  pHead + 9*sizeof(int) = pTail;
int arr1[10];
int pHead1 = (int)&arr[0];
int pTail1 = (int)&arr[9];
printf("%d
",pTail1 - pHead1);//36

运算关系

判断回文

char name[5] = {'m','a','d','a','m'};
char *pH = &name[0];char *pT = &name[4];
int flag = 1;
while(pH < pT) {//指针关系判断
    if(*pH == *pT) {
        pH++;
        pT--;
    }else {
        flag = 0;
        break;
    }
}
if(flag ==1) {
    printf("回文!");
}else {
    printf("不是回文!");
}

数组与指针

一维数组的访问:

本质法---数组偏移法
下标法---通用访问方法

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(int i = 0;i < 10;i++)
{
    printf("%d
",*(arr+i));//偏移法
}
for(int i = 0;i < 10;i++) 
{
    printf("%d
",arr[i]);//通用下标法
}
//数组名是指针常量方可唯一的表示一个数组。数组名是数组的唯一标识符。
//一维的数组名可以赋值给以及指针,二维不可以。
printf("arr     =%p
",arr);//数组名的形式访问数组首地址 
printf("arr + 1 =%p
",arr + 1);//首地址+1个int类型的大小4

printf("&arr[0]     =%p
",&arr[0]);//取数组首元素的地址
printf("&arr[0] + 1 =%p
",&arr[0]+1);//数组首元素的地址+1个int的大小

数组名能干的指针能干,数组名不能干的指针也能干

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for(int i = 0;i < 10;i++)
{
    printf("%d
",*(arr+i));//偏移法
}
for(int i = 0;i < 10;i++) 
{
    printf("%d
",arr[i]);//通用下标法
}
int *p = arr;
//可以直接替换
for(int i = 0;i < 10;i++)
{
    printf("%d
",*(p+i));//偏移法
}
for(int i = 0;i < 10;i++) 
{
    printf("%d
",p[i]);//通用下标法
}

for(int i = 0;i < 10;i++) {
    printf("%d
",*p++);
    printf("%d
",*(p++));
    printf("%d
",arr[0]++);//完全等价,++的优先级高于*
}


二维数组与指针

二维数组的访问方式

int arr[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
for(int i = 2;i >= 0;i--) {
    for(int j = 3;j >= 0;j--) {
        printf("a[%d][%d] = %#x
",i,j,&arr[i][j]);
    }
    printf("==================
");
}
printf("arr    = %#p arr+1    = %#x arr+2    = %#x
",arr,arr+1,arr+2);
printf("arr[0] = %#p arr[0]+1 = %#x arr[0]+2 = %#x
",arr[0],arr[0]+1,arr[0]+2)

/*
a[2][3] = 0x61fea4
a[2][2] = 0x61fea0
a[2][1] = 0x61fe9c
a[2][0] = 0x61fe98
==================
a[1][3] = 0x61fe94
a[1][2] = 0x61fe90
a[1][1] = 0x61fe8c
a[1][0] = 0x61fe88
==================
a[0][3] = 0x61fe84
a[0][2] = 0x61fe80
a[0][1] = 0x61fe7c
a[0][0] = 0x61fe78
==================
arr    = 0X0061FE78 arr+1    = 0x61fe88 arr+2    = 0x61fe98
arr[0] = 0X0061FE78 arr[0]+1 = 0x61fe7c arr[0]+2 = 0x61fe80
*/


printf("*arr    = %#p *arr+1    = %#x *arr+2    = %#x
",*arr,*arr+1,*arr+2);
printf("&arr[0] = %#p &arr[0]+1 = %#x &arr[0]+2 = %#x
",a&rr[0],&arr[0]+1,&arr[0]+2);
//两者互为逆运算
//a-a[0]:对a解引用(*)会产生a[0];对a[0]引用(&)会产生a;
printf("arr[3][2] = %d
",*(*(arr+2)+1));
//arr[i]    <=> *(arr+i)
//arr[i][j] <=> *(*(arr+i)+j)

往指定的地址写如数据

int *p = (int*)0x12345678;//指定的地址,c++要求严格的数据类型
*p = 300;
//很容导致内存奔溃 
原文地址:https://www.cnblogs.com/intelwisd/p/8262006.html