首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >深入理解指针(5)

深入理解指针(5)

作者头像
用户11831438
发布2025-12-30 13:27:55
发布2025-12-30 13:27:55
1230
举报
1.sizeof和strlen的对比
1.1sizeof

在学习操作符的时候,学习了sizeof,sizeof计算变量所占内存空间的大小单位是字节如果操作数是类型的话,计算的是用该类型所创建变量所占内存空间的大小。

sizeof只关注占用内存空间的大小,不在乎内存中存放什么数据。

比如:

代码语言:javascript
复制
int main()
{
	int a = 10;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof a);
	printf("%d\n", sizeof(int));
	//printf("%d\n", sizeof int);
	return 0;
}

我们通过编译器得出上面代码的结果:

当我们看到return 0;语句的上一行也就是printf("%d\n",sizeof int);当编译器执行到这一句的时候,会报错,这也说明了这句代码是一个错误代码,当我们想知道类型的大小的时候,类型需要写在括号内部,正确写法为sizeof(int)。

1.2 strlen

strlen是C语言库函数,其功能是求字符串长度,使用的时候需要包含头文件string.h。原型如下:

其统计的是\0之前字符串中字符的个数。strlen函数会一直向后找\0字符,直到找到为止,如果找不到\0,它会给我们返回一个随机值。在使用strlen函数求字符串的个数的时候,我们需要提供字符串的首地址。

代码语言:javascript
复制
int main()
{
	char arr1[] = { 'a','b','c' };
	char arr2[] = "abc";
	printf("%d\n", strlen(arr1));
	printf("%d\n", strlen(arr2));
	printf("\n");
	printf("%d\n", sizeof(arr1));
	printf("%d\n", sizeof(arr2));

	return 0;
}

通过运行结果,我们可以看出,当strlen函数找不到\0的时候,会返回一个随机值。

2.数组和指针笔试题解析

数组名的意义:

sizeof(数组名):这里的数组表示整个数组,计算的是整个数组的大小;

&数组名:这里的数组名表示整个数组,取出的是整个数组的地址;

除此之外,数组名表示数组首元素的地址。

2.1 一维数组
代码语言:javascript
复制
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a+0));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a+1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(*&a));
	printf("%d\n", sizeof(&a+1));
	printf("%d\n", sizeof(&a[0]));
	printf("%d\n", sizeof(&a[0]+1));
	return 0;
}

代码解析: 1、 printf("%d\n", sizeof(a));a单独放在sizeof中,a表示整个数组,sizeof(a)计算的是整个数组的大小,结果是16 2、 printf("%d\n", sizeof(a+0));//a没有单独放在sizeof中,a表示数组首元素的地址,a+0表示第一个元素的地址,地址的大小是4/8个字节 3、 printf("%d\n", sizeof(*a));//a没有单独放在sizeof中,a表示数组首元素的地址,*a对地址解引用,代表是数组首元素,结果是4 4、printf("%d\n", sizeof(a+1));//a没有单独放在sizeof中,a表示数组首元素的地址,指针+1表示跳过一个元素,a+1表示数组第二个元素的地址,地址的大小是4/8个字节 5、 printf("%d\n", sizeof(a[1]));//a[1]就是数组下标为1的元素,大小是4个字节 6、printf("%d\n", sizeof(&a));//&a取出的是整个数组的地址,是地址,大小就是4/8个字节,&a的特殊体现在+-整数 7、printf("%d\n", sizeof(*&a));//&a取出的是整个数组的地址,它的类型是int(*)[4],对于数组指针解引用,访问的是整个数组(对整个数组解引用得到的就是整个数组),结果是16(*&a==a) 8、printf("%d\n", sizeof(&a+1));//&a取出的是整个数组的地址,&a+1表示下一个类型是int (*)[4]的数组的整个数组的地址,是地址就是4/8个字节 9、printf("%d\n", sizeof(&a[0]));//a[0]表示数组第一个元素,&a[0]表示取出第一个元素的地址,是地址,大小是4/8个字节 10、 printf("%d\n", sizeof(&a[0]+1));//&a[0]表示取出第一个元素的地址,&a[0]+1表示取出数组第二个元素的地址,大小是4/8( &a[ 0 ]+1 == &a[1] )

2.2 字符数组

代码1:

代码语言:javascript
复制
#include <stdio.h>
 int main()
 {
 char arr[] = {'a','b','c','d','e','f'};
 printf("%d\n", sizeof(arr));
 printf("%d\n", sizeof(arr+0));
 printf("%d\n", sizeof(*arr));
 printf("%d\n", sizeof(arr[1]));
 printf("%d\n", sizeof(&arr));
 printf("%d\n", sizeof(&arr+1));
 printf("%d\n", sizeof(&arr[0]+1));
 return 0;
 }

代码解析:

1、printf("%d\n", sizeof(arr));//arr单独放在sizeof中,表示整个数组的地址,计算的是整个数组的大小,结果是6。 2、printf("%d\n", sizeof(arr + 0));//arr不是单独放在sizeof中,表示数组首元素的地址,arr+0是数组第一个元素的地址,结果是4/8。 3、 printf("%d\n", sizeof(*arr));//arr不是单独放在sizeof中,表示数组首元素的地址,*arr表示数组下标为0的元素,大小是1。 4、 printf("%d\n", sizeof(arr[1]));//arr[1]表示数组下表为1的元素,大小是1。 5、printf("%d\n", sizeof(&arr));//&arr取出的是整个数组的地址,大小是4/8。 6、printf("%d\n", sizeof(&arr + 1));//&arr取出的是整个数组的地址,&arr+1是下一个数组的整个数组的地址,大小是4/8。 7、printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是数组下标为0的地址,&arr[0]+1是数组下标为1的地址,大小是4/8。

注意:地址的大小与元素类型无关,只与当前环境有关,x64环境下大小是8个字节,x86环境下是4个字节。

代码2:

代码语言:javascript
复制
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };//该字符数组中没有\0
	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 0));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(&arr + 1));
	printf("%d\n", strlen(&arr[0] + 1));
	return 0;
}

代码解析:

1、printf("%d\n", strlen(arr));//arr表示数组首元素的地址,但由于该数组中没有\0,所以结果是一个随机值。 2、printf("%d\n", strlen(arr + 0));//arr表示数组首元素的地址,arr+0表示数组第一个元素的地址, 但由于该数组中没有\0,所以结果是一个随机值。 3、printf("%d\n", strlen(*arr));//arr表示数组首元素的地址,*arr是数组第一个元素,但由于strlen函数的参数中只能传地址,所以这句代码是error。 4、printf("%d\n", strlen(arr[1]));arr[1]表示数组下标为1的元素,但由于strlen函数的参数中只能传地址,所以这句代码是error。 5、printf("%d\n", strlen(&arr));//&arr取出的是整个数组的地址,从数组的地址也就是数组的起始位置开始向后数字符串的长度,要找\0,但由于该数组中没有\0,所以结果是一个随机值。 6、printf("%d\n", strlen(&arr + 1));//&a取出的是整个数组的地址,&a+1表示下一个类型是char (*)[6]的数组的整个数组的地址,因为\0不知道何时出现,所以结果是随机值。 7、printf("%d\n", strlen(&arr[0] + 1));//&arr[0]+1是数组下标为1的元素的地址,但由于该数组中没有\0,所以结果是一个随机值。

代码3:

代码语言:javascript
复制
int main()
 {
 char arr[] = "abcdef";
 printf("%d\n", sizeof(arr));
 printf("%d\n", sizeof(arr+0));
 printf("%d\n", sizeof(*arr));
 printf("%d\n", sizeof(arr[1]));
 printf("%d\n", sizeof(&arr));
 printf("%d\n", sizeof(&arr+1));
 printf("%d\n", sizeof(&arr[0]+1));
 return 0;
 }

代码解析:

1、printf("%d\n", sizeof(arr));//arr单独存放在sizeof中,计算的是整个数组的大小,结果是7。 2、printf("%d\n", sizeof(arr + 0));//arr表示数组首元素的地址,arr+0表示数组第一个元素的地址,大小是4/8。 3、printf("%d\n", sizeof(*arr));//arr表示数组首元素的地址,*arr表示数组首元素,结果是1。 4、printf("%d\n", sizeof(arr[1]));//结果是1。 5、printf("%d\n", sizeof(&arr));//&arr取出的是整个数组的地址,大小是4/8。 6、printf("%d\n", sizeof(&arr + 1));//&arr取出的是整个数组的地址,&arr+1取出的是下一个数组的地址类型为char (*)[7]的地址,是地址,大小是4/8。 7、printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是数组下标为1的地址,大小是4/8。

代码4:

代码语言:javascript
复制
int main()
 {
 char arr[] = "abcdef";
 printf("%d\n", strlen(arr));
 printf("%d\n", strlen(arr+0));
 printf("%d\n", strlen(*arr));
 printf("%d\n", strlen(arr[1]));
 printf("%d\n", strlen(&arr));
 printf("%d\n", strlen(&arr+1));
 printf("%d\n", strlen(&arr[0]+1));
 return 0;
 }

代码解析:

char arr[] = "abcdef";//字符串中有\0,strlen函数求的是\0之前的字符个数 1、printf("%d\n", strlen(arr));//arr表示数组首元素的地址,结果是6 2、 printf("%d\n", strlen(arr + 0));//arr+0就是&arr[0]表示数组首元素的地址,结果是6 3、printf("%d\n", strlen(*arr));//arr表示数组首元素的地址,*arr得到是首元素,代码错误 4、printf("%d\n", strlen(arr[1]));//arr[1]是数组下标为1的元素,代码错误 5、printf("%d\n", strlen(&arr));//&arr取出的是整个数组的地址,整个数组的地址也是从首元素地址开始,结果是6 6、printf("%d\n", strlen(&arr + 1));//&arr取出的是整个数组的地址,&arr+1取出的是下一个数组的整个数组的地址,随机值 7、printf("%d\n", strlen(&arr[0] + 1));//&arr[0]是数组下标为0的元素的地址,&arr[0]+1==&arr[1]是数组下表为1的元素的地址,结果是5

注意:strlen函数的参数要的是地址

代码5:

代码语言:javascript
复制
int main()
 {
 char *p = "abcdef";
 printf("%d\n", sizeof(p));
 printf("%d\n", sizeof(p+1));
 printf("%d\n", sizeof(*p));
 printf("%d\n", sizeof(p[0]));
 printf("%d\n", sizeof(&p));
 printf("%d\n", sizeof(&p+1));
 printf("%d\n", sizeof(&p[0]+1));
 return 0;
 }

代码解析:

char* p = "abcdef";//p是一个指针变量,字符串为常量字符串,p中存放的是字符串首元素的地址。 1、 printf("%d\n", sizeof(p));//p是一个指针变量,一个指针变量大小是4/8。 2、printf("%d\n", sizeof(p + 1));//p中存放的是字符串首元素的地址,指针+1跳过一个字符,p+1表示b的地址,结果是4/8 3、 printf("%d\n", sizeof(*p));//p中存放的是字符串首元素的地址,*p表示a,结果是1 4、 printf("%d\n", sizeof(p[0]));//p[0]==*(p+0),表示a,结果是1 5、printf("%d\n", sizeof(&p));//p中存放的是字符串首元素的地址,&p是一个二级指针,存放的是p自己的地址,结果是4/8 6、printf("%d\n", sizeof(&p + 1));//&p是一个二级指针,存放的是p自己的地址,&p + 1是地址,结果是4/8 7、 printf("%d\n", sizeof(&p[0] + 1));//p[0]==*(p+0),表示a,&p[0]表示a的地址,&p[0] + 1表示b的地址,结果是4/8。 代码6:

代码语言:javascript
复制
#include <stdio.h>
 #include <string.h>
 int main()
 {
 char *p = "abcdef";
 printf("%d\n", strlen(p));
 printf("%d\n", strlen(p+1));
 printf("%d\n", strlen(*p));
 printf("%d\n", strlen(p[0]));
 printf("%d\n", strlen(&p));
 printf("%d\n", strlen(&p+1));
 printf("%d\n", strlen(&p[0]+1));
 return 0;
 }

代码解析:

1、printf("%d\n", strlen(p));//p中存放的是字符串首元素的地址,结果是6 2、printf("%d\n", strlen(p + 1));//p+1是b的地址,结果为5 3、printf("%d\n", strlen(*p));//error 4、printf("%d\n", strlen(p[0]));//p[0]==*(p+0)error 5、printf("%d\n", strlen(&p));//随机值 6、printf("%d\n", strlen(&p + 1));//随机值 7、printf("%d\n", strlen(&p[0] + 1));//p[0]==*(p+0),表示a,&p[0]表示a的地址,&p[0] + 1表示b的地址,结果是5。

2.3 二维数组
代码语言:javascript
复制
int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a[0][0]));
	printf("%d\n", sizeof(a[0]));
	printf("%d\n", sizeof(a[0] + 1));
	printf("%d\n", sizeof(*(a[0] + 1)));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(*(a + 1)));
	printf("%d\n", sizeof(&a[0] + 1));
	printf("%d\n", sizeof(*(&a[0] + 1)));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a[3]));
	return 0;
}

代码解析:

int a[3][4] = { 0 };//二维数组的数组名表示数组的首元素,二维数组的首元素就是第一行的数组名a[0]。 1、printf("%d\n", sizeof(a));//a单独在sizeof中,计算的是整个数组的大小,结果的48 2、printf("%d\n", sizeof(a[0][0]));//a[0][0]是第一行下标为0的元素,大小是4 3、printf("%d\n", sizeof(a[0]));//a[0]是二维数组第一行的数组名,并且单独在sizeof中,那么a[0]就表示整个第一行的地址,计算的是第一行一维数组的大小,结果是16 4、printf("%d\n", sizeof(a[0] + 1));//a[0]是二维数组第一行的数组名,表示第一行一维数组的首元素的地址,a[0] + 1为第一行第二个元素的地址,结果是4/8 5、printf("%d\n", sizeof(*(a[0] + 1)));//第一行第二个元素,结果是4 6、printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,这里只能表示数组首元素的地址,也就是第一行的地址,a+1就是第二行的地址,结果是4/8 7、printf("%d\n", sizeof(*(a + 1)));//a+1表示整个第二行的地址,*(a+1)是整个第二行,结果是16,a+1==&a[1],*(a+1)==*&a[1]==a[1] 8、printf("%d\n", sizeof(&a[0] + 1));//&a[0]取出的是整个第一行的地址,&a[0] + 1是跳过一个类型为int (*)[4]的数组,表示整个第二行的地址,结果是4/8 9、printf("%d\n", sizeof(*(&a[0] + 1)));//&a[0] + 1表示整个第二行的地址,*(&a[0] + 1)是对整个第二行解引用,求的是整个第二行的大小,结果是16 10、printf("%d\n", sizeof(*a));//表示整个第一行,结果是16 11、不知道当小伙伴看到sizeof(a[3]的时候,心里是否会有疑问?整个二维数组不就只有三行吗?数组名分别是a[0],a[ 1],a[ 2]吗?怎么这里写了一个a[3]呢?是不是博主自己写错了?当然不是这样的,其实a[ 3]是真实存在的,sizeof在计算变量、数组的大小的时候,是通过类型来推导的,不会真实的去访问内存空间,所以printf("%d\n", sizeof(a[3]));的结果为4/8。

3.指针运算笔试题解析
3.1 题⽬1
代码语言:javascript
复制
#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;
 }
//程序的结果是什么?

根据上面的画图,我们可以很清晰的看出结果分别是2和5。

3.2 题⽬2
代码语言:javascript
复制
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?

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;
}

通过分析题目,可以很清晰的看出这道题考的内容是指针+-整数。、

最终结果是00100014,00100001,00100004

3.3 题⽬3
代码语言:javascript
复制
#include <stdio.h>
 int main()
 {
 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 p = a[0];
 printf( "%d", p[0]);
 return 0;
 }

这道题我们先来看看二维数组中的内容,{(0,1),(2,3),(4,5)},我们可以很清晰的看出这给大括号中的内容是由三个小括号组成,根据我们前面所学习的内容,可以快速反应出这是个逗号表达式,整个表达式的结果是最后一个表达式的结果,所以二维数组中的内容应该是{1,3,5}

指针p中存放的是二维数组第一行的数组名,数组名又表示一维数组首元素的地址,所以p中真实存放的应该是a[0][0]的地址,p[0]==*(p+0),所以最终打印的结果应该是1。

3.4 题⽬4
代码语言:javascript
复制
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

a[5][5]是一个5行5列的二维数组,int (*p)[4] 是一个数组指针,存放的是数组的地址,数组指针的类型是int (*)[4],这里面的4表示数组中有4个元素,|指针-指针| 的结果是两个指针之间的元素个数,所以printf("%d",&p[4][2] - &a[4][2])的结果是-4; printf("%p",&p[4][2] - &a[4][2]);是将-4的地址以16进制的形式打印出来,我们知道是以二进制的形式在内存中存储(并且是以补码的形式),-4的补码是11111111111111111111111111111100,最终的结果是FFFFFFFC。

注意:%p是打印地址的,认为内存中存放的补码就是地址,并且以16进制的形式打印

3.5 题目5
代码语言:javascript
复制
int main()
{
	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", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

int* ptr1 = (int*)(&aa + 1); &aa是去除整个二维数组的地址,&aa + 1是跳过整个二维数组 (int*)(&aa + 1)将类型强转成int*类型 int* ptr2 = (int*)(*(aa + 1)); 上面代码中的aa单独出现,表示数组首元素的地址,二维数组首元素的地址是第一行的地址 aa + 1是跳过一个类型为int(*)[5]的数组,表示第二行的地址 *(aa + 1)==aa[1],aa[1]为二维数组第二行的数组名,这里的数组名表示数组首元素的地址

所以最终结果为5,10。

3.6 题目6
代码语言:javascript
复制
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}

根据上图,我们可以得出打印结果为“at”。

3.7 题目7
代码语言:javascript
复制
int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *-- * ++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
	return 0;
}

写到这里,指针这一章节算是完美撒花啦!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.sizeof和strlen的对比
    • 1.1sizeof
    • 1.2 strlen
  • 2.数组和指针笔试题解析
    • 2.1 一维数组
    • 2.2 字符数组
    • 2.3 二维数组
  • 3.指针运算笔试题解析
    • 3.1 题⽬1
    • 3.2 题⽬2
    • 3.3 题⽬3
    • 3.4 题⽬4
    • 3.5 题目5
    • 3.6 题目6
    • 3.7 题目7
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档