指针————sizeof/strlen中参数含义

这篇文章主要总结了一系列的sizeof和strlen常见的参数含义。

一、数组

int a[]={1,2,3,4};
1.sizeof(a);//4*4=16bit
2.sizeof(a+0);//4/8bit
3.sizeof(*a);//4bit
4.sizeof(a+1);//4bit
5.sizeof(a[1]);//4bit
6.sizeof(&a+1);//4/8bit
7.sizeof(&a[0]);//4/8bit
8.sizeof(&a[0]+1);//4/8bit
9.sizeof(&a);//4/8bit
10.sizeof(*&a);//4*4=16bit

我们知道数组名都代表数组首元素的地址,二维数组名代表第一行数组的地址。但有两个例外:如果在sizeof内部的数组名代表整个数组的地址;在&后面的数组名也代表整个数组的地址。只要是地址,大小就是4或8个字节。

1.a原本是数组名代表首元素地址,但在sizeof内部,所以代表整个数组的地址,由于是int类型,且一共有4个元素,大小就是4*4=16字节

2.a+0代表数组第一个元素的地址,只要是地址就是4或8个字节

3.*a代表第一个元素,第一个元素是int类型,所以大小为4个字节

4.a+1代表数组第二个元素的地址,只要是地址就是4或8个字节

5.a[1]代表数组第二个元素,为int类型,所以大小是4个字节

6.&a+1中&a代表整个数组的地址,+1后跳过整个数组,但仍然是某一个元素的地址,是地址就是4或8个字节

7.&a[0]代表首元素的地址,也是地址,那么就是4或8个字节

8.&a[0]+1代表第二个元素的地址,是地址就是4或8个字节

9.&a中就是我们前面讲的整个数组的地址,只要是地址就是4或8个字节

10.*&a代表先取出整个数组的地址,再对它解引用那么还是整个数组,所以大小为4*4=16个字节

二、字符数组

char arr[]={'a','b','c','d','e','f'};
1.sizeof(arr);//6bit
2.sizeof(arr+0);//4/8bit
3.sizeof(*arr);//1bit
4.sizeof(arr[1]);//1bit
5.sizeof(&arr);//4/8bit
6.sizeof(&arr+1);//4/8bit
7.sizeof(&arr[0]+1);//4/8bit

1.arr在sizeof内部即代表整个数组,整个数组为char类型只有1个字节,故有6个元素就是6*1=6个字节

2.arr代表首元素的地址,arr+1代表第二个元素的地址,是地址就是4或8个字节

3.*arr代表首元素,首元素为char类型所以大小为1个字节

4.arr[1]代表第二个元素,第二个元素为char类型,所以大小为1个字节

5.&arr代表整个数组的地址,只要是地址就是4或8个字节

6.&arr代表整个数组的地址,&arr+1代表跳过整个数组之后的地址,但仍然是地址,只要是地址就是4或8个字节

7.&arr[0]+1代表第二个元素的地址,只要是地址就是4或8个字节

char arr[]={'a','b','c','d','e','f'};
1.strlen(arr);//随机值
2.strlen(arr+1);//随机值
3.strlen(*arr);//error
4.strlen(arr[1]);//error
5.strlen(&arr);//随机值
6.strlen(&arr+1);//随机值
7.strlen(&arr[0]+1);//随机值

strlen函数中的形参是指针类型,所以传递过去的参数必须是地址或指针类型,且strlen是看\0的,只要看到\0才会停下。

1.arr代表数组首元素的地址,strlen从首元素开始往后数,但字符数组中没有\0,所以会一直往后数,故返回随机值

2.arr+1代表数组第二个元素的地址,strlen从第二个元素往后数,还是没有找到\0,会返回一个随机值

3.*arr代表数组首元素即’a',此时a的ASCⅡ码值为97,strlen把97当作地址接受,所以报错非法访问

4.arr[1]代表数组第二个元素,道理与3.一样,返回错误

5.&arr取出整个数组的地址,strlen向后数直到遇到\0,返回随机值

6.&arr+1代表跳过该数组,从数组的后一个向后数,直到遇到\0结束,返回随机值

7.&arr[0]+1代表数组第二个元素的地址,从数组第二个元素开始往后数,直到遇到\0终止,返回\0

三、字符串

char*p="abcdef";
1.sizeof(p);//4/8bit
2.sizeof(p+1);//4/8bit
3.sizeof(*p);//1bit
4.sizeof(p[0]);//1bit
5.sizeof(&p);//4/8bit
6.sizeof(&p+1);//4/8bit
7.sizeof(&p[0]+1);//4/8bit

1.p为指针,sizeof(p)代表指针的地址,只要是地址就是4或8个字节

2.p代表首元素地址,p+1代表'b'的地址,只要是地址就是4或8个字节

3.*p代表首元素'a',首元素是char类型,大小就是1个字节

4.p[0]代表首元素'a',首元素是char类型,大小就是1个字节

5.&p代表整个字符串的地址,地址就是4或8个字节

6.&p+1代表跳过p字符串之后的地址,只要是地址就是4或8个字节

7.&p[0]+1代表第二个元素的地址,只要是地址就是4或8个字节

char *p="abcdef";
1.strlen(p);//6
2.strlen(p+1);//5
3.strlen(*p);//error
4.strlen(p[0]);//error
5.strlen(&p);//随机值
6.strlen(&p+1);//随机值
7.strlen(&p[0]+1);//5

1.p代表首元素地址,从'a'开始往后数直到\0结束,字符串自带\0,所以6

2.p+1代表第二个元素的地址,从'b'开始往后数直到\0结束,字符串自带\0,所以5

3.*p代表第一个元素,strlen只接受地址

4.p[0]代表第一个元素,而strlen只能接收地址

5.&p代表p指针的地址,strlen从p指针的地址往后数直到\0,所以随机值

6.&p+1代表p后面某一元素的地址,与5.同理

7.&p[0]+1代表第二个元素的地址,与2.同理

四、二维数组

int a[3][4]={0};
1.sizeof(a);//48bit
2.sizeof(a[0][0]);//4bit
3.sizeof(a[0]);//16bit
4.sizeof(a[0]+1);//4/8bit
5.sizeof(*a[0]+1);//4bit
6.sizeof(a+1);//4/8bit
7.sizeof(*(a+1));//16bit
8.sizeof(&a[0]+1);//4/8bit
9.sizeof(*(&a[0]+1));//16bit
10.sizeof(*a);//16bit
11.sizeof(a[3]);//16bit

1.a在sizeof内部代表整个数组,那么整个数组为int类型,大小为3*4*4=48字节

2.a[0][0]代表首元素,作为int类型首元素大小为4个字节

3.a[0]代表第一行的数组名,放在sizeof内部就代表整行数组,即第一行的数组,所以大小为4*4=16个字节

4.a[0]作为第一行的数组名没有单独放在sizeof内部,所以代表首元素的地址,a[0]+!即代表第二个元素的地址,只要是地址就是4或8个字节

5.*a[0]+1代表4.中第二个元素的地址解引用,由于是int类型,所以大小是4个字节

6.a为首元素地址即第一行的地址,a+1代表第二行的地址,只要是地址就是4或8个字节

7.*(a+1)代表将第二行的地址解引用,大小为4*4=16个字节

8.&a[0]代表第一行的地址,+1后代表第二行的地址,只要是地址都是4或8个字节

9.*(&a[0]+1)代表将第二行的地址解引用,大小为4*4=16个字节

10.*a代表对首元素即第一行的地址解引用,大小为4个字节

11.a[3]代表第四行的数组名,在sizeof内部就代表第四行整个数组,大小为4*4=16个字节

下面我们来看几道例题,更好的应用

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后代表跳过整个数组之后的地址,(int*)强制转换是将数组指针强制转换成了整型指针,指针运算时走的步数变少,打印出的*(ptr-1)就是将ptr指针向后退一步,又回到了数组中,即指向了5。*(a+1)代表a作为数组名是首元素地址,+1后为第二个元素,解引用后指向2,所以结果是2 5.


struct test{
    int name;
    char*pname;
    short date;
    char cha[2];
    short ba[4];
}*p;
int main(){
    p=(struct test*)0x100000;
    printf("%p",p+0x1);
    printf("%p",(unsigned long)p+0x1);
    printf("%p",(unsigned int*)p+0x1);
   }

这个是结构体,打印出来应该是0x100014 0x100001 0x100004

已知该结构体有20个字节大小,假设p的值为0x100000(%p打印地址)

1.0x1是十六进制的1,那么p+0x1代表p结构体加上sizeof(结构体),即p+十六进制的20。计算可知十六进制的20是14,所以结果为0x100000+0x000014=0x100014

2.p被强制类型转换成了unsigned long成为了整数,整数+1就只是+1,所以为0x100000+0x1=0x100001

3.p被强制类型转换成立整型指针,int*类型+1是+4个字节,所以应该为0x100000+4=0x100004


int main(){
    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是一个一维数组,%x用十六进制打印

1.ptr1是一个指针,&a+1之前讲过是指整个数组后面的一个地址,经过(int*)强制类型转换从数组指针转换成整形指针步数变小,ptr1向前走-1那么就指向4

2.ptr2也是一个指针(int)a+1首先a作为数组名是数组首元素地址,被强制类型转换成为整型后+1,之后(int*)强制类型转换成为整型指针


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

结果:1

我们要注意a[3][2]是一个逗号表达式,所以a数组中存放应该是1 3,5 0,0 0 。p是一个指针,指向a[0]为第一行数组,p[0]代表第一行数组的首元素即1


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

这是一个二维数组,p是一个指向4个元素的int类型元素的数组指针,之后将a的首元素地址给p,

由图所示:

 我们知道,指针-指针=两指针间元素个数

由图可知都是低地址-高地址=-4,-4用%d打印时-4;-4用%p打印即打印-4的地址,通过我们之前讲的二进制原码反码补码来计算,-4的原码是10000000 00000000 00000000 00000100,-4的反码是11111111 11111111 11111111 11111011,-4的补码是11111111 11111111 11111111 11111100,即FF FF FF FC。

所以打印结果为:FFFFFFFC  -4

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妮妮妮妮没事吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值