指针深刻理解

一、基础知识

①指针加减一个整数时,会根据指针指向的类型的大小进行偏移

通过几道题深刻理解指针

Ⅰ.

#include<stdio.h>
int main()
{
    int a[5]={1,2,3,4,5};
    int* ptr=(int*)(&a+1);
    printf("%d,%d",*(a+1),*(ptr-1));
    return 0;
}

&a表示整个数组的地址,数组的地址放数组指针中,+1跳过整个数组,指向5后面

&a+1:指向数组开头的指向+1跳过一整个数组,指向5后面

(int*)(&a+1):表示将int(*)[5]类型强制转换为int*类型,只是类型变了,值未变

int* ptr=(int*)(&a+1):再赋给ptr,ptr是整型指针

ptr-1:ptr-1往前移动一个int型,即指向5前面

%d ,*(ptr-1):然后解引用就是5

a:数组首元素1的地址,即指向1的前端

a+1:a是int类型的,+1跳过一个int,指向2前端,是2的地址

%d ,*(a+1):解引用是2

 

Ⅱ.

struct Test
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p=(struct Test*)0x100000;

int main()
{
    printf("%p\n",p+0x1);
    printf("%p\n",(unsigned long)p+0x1);
    printf("%p\n",(unsigned int*)p+0x1);
    return 0;
}

p:结构体指针,+1跳过一个结构体大小,而结构体Test类型的变量大小是20个字节(十进制)

0x1:十六进制的1也是十进制的1

%pL:打印地址

%p, p+0x1:p+十六进制的1,十进制的20转为十六进制是14,即0x100000+(0×1×sizeof(struct Test)=0x100000+14=0x100014

(unsigned long)p:将p当成无符号长整型

%p, (unsigned long)p+0x1:整数加1就是加1,为0x100000+0×1=0x100001。指针加减才要根据指针类型判断加几个字节

(unsigned int*)p:无符号整型指针

%p, (unsigned int*)p+1:跳过一个无符号整型的大小,即0x100000+(0×1×sizeof(unsigned int))=0x100000+4=0x100004

Ⅲ.

    int a[4]={1,2,3,4};
    int* ptr1=(int*)(&a+1);
    int* ptr2=(int*)((int)a+1);
    printf("%x,%x",ptr1[-1],*ptr2);

&a:取出数组的地址,即1的地址,类型是数组指针

&a+1:数组指针+1跳过一个数组,指向4后面

%x, ptr[-1]:*(ptr1+(-1))=*(ptr1-1)=4

注意区别:若a=0x0012ff40,则a+1=0x0012ff44,指向a后面一个元素的地址;(int)a+1=0x0012ff41,指向a的4个字节中第一个字节的地址

1写成十六进制是0x00000001,而计算机大多数都是小端存储,低位放低地址,高位放高地址,存的是01000000

(int)a:a数组首元素1的地址,现将这个地址看成整数

(int)a+1:向右移动一个字节,指向01后面的00,并将这个值强制类型转换为int*,赋给ptr2

%x, ptr2:int类型的指针,解引用访问一个整型,从01后面的00向后访问4个字节的内容:00 00 00 02,因为小端存储,取出来是02 00 00 00,十六进制打印不会打印首位的0,即打印2000000

%x:按十六进制打印

Ⅳ.

    int a[3][2]={(0,1),(2,3),(4,5)};
    int* p;
    p=a[0];
    printf("%d",p[0]);

逗号表达式:{(0,1),(2,3),(4,5)}={1,3,5}。对于数组来说是不完全初始化,数组a={1,3,5,0,0,0}

a[0]:第一行的数组名,没放sizeof内部和无&,表示

p=a[0]:将首元素a[0][0]的地址赋给p,即&a[0][0]

%d, p[0]:等于*(p+0)=*p,整型指针解引用访问一个整型,访问1

Ⅴ.

    int a[5][5];
    int (*p)[4];
    p=a;
    printf("%p,%d",&p[4][2]-&a[4][2],&p[4][2]-&a[4][2]);

int (*p)[4]:p是数组指针,指向的数组有4个元素,每个元素是int型的,p+1就是跳过一个数组,也就是4个整型

p=a:将a的地址赋给p

p[4][2]:*(*(p+4)+2)

%d, &p[4][2]-&a[4][2]:两指针相减得到它们之间的元素个数,小-大得-4,如图

%p, &p[4][2]-&a[4][2]:打印地址,地址无原、反、补码的概念,就相当于无符号数,将存的补码转成16进制打印出来,如图

Ⅵ.

    int aa[2][5]={1,2,3,4,5,6,7,8,9,10};
    int* ptr1=(int*)(&aa+1);
    int* ptr2=(int*)(*(aa+1));
    printf("%d,%d\n",*(ptr1-1),*(ptr2-1));

&aa:整个数组的地址

&aa+1:跳过整个数组,指向10后面

int* ptr1=(int*)(&aa+1):ptr1指向10后面

*(ptr1-1):ptr1向前移动一个int长度,指向10前面,解引用就是10

aa:第一行元素的地址

aa+1:表示第二行首元素的地址,指向6前面

*(aa+1):等于aa[1],解引用得到第二行,也相当于拿到第二行数组名,而没放在sizeof内部和&后,所以表示第二行数组名的首元素6的地址

int* ptr2=*(aa+1):6的地址赋给ptr2

*(ptr2-1):ptr2向前移动一个int到5,解引用得到5

Ⅶ.

    char* a[]={"work","at","alibaba"};
    char** pa=a;
    pa++;
    printf("%s\n",*pa);

char* a[ ]:a是指针数组,放的元素是char*类型的,分别将'w'、'a'、'a'的地址放在数组中

a:数组名表示首元素地址

char** pa=a:将首元素地址(一级指针)放在pa中,pa是二级指针,指向数组a的第一个元素'w'的地址

pa++:向后移动一个char*类型,指向数组a的第二个元素'a'的地址

*pa:解引用得到pa指向的'a'的地址

%s, *pa:得到'a'的地址就访问所在的元素'at'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值