c语言数组与指针题目理解

strlen()和sizeof区别:

名称    区别                                              
sizeof

1.sizoef是操作符

2.sizoef计算的是操作数所占内存的大小,单位是字节

3.不关注内存中存放什么数据

strlen

1.strlen是库函数,使用需要包含头文件string.

2.strlen是求字符串长度的,统计的是'\0'之前字符的个数

3.只关注内存中是否有'\0',如果没有'\0',就会持续往往后面找,可能会导致越界

 

数组名的理解:

1.sizoef(数组名),数组名单独放在sizeof括号内,这里的数组名表示整个数组,计算的是整个数组的大小。

2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。

3.除此之外所有的数组名都表示首元素的地址。

有了上面两个知识点的了解,我们对接下来的题目会更好的理解。


一维数组

#include<stdio.h>
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;
}

运行一下:

这里为vs2002,x64环境。后续代码运行结果都是此环境。

解析:

1.第一个就是sizeof的括号里面单独放着数组名,数组名表示的是整个数组,所以计算的是整个数组的大小,数组有4个元素,都是int类型的,所以结果为4 * int = 16

2.这里sizeof里面没有单独放数组名,所以现在的数组名表示首元素的地址,首元素的地址+0还是首元素的地址,地址在x86环境下大小为4,在x64环境下大小为8,所以结果为8

3.这里*a,a是首元素地址,对首元素地址进行解引用,得到1,1是整型,大小为4,所以结果为4

4.这里a+1,a是首元素地址,a+1就是第二个元素地址,所以结果为8

5.这里arr[1],这个[]是下标应用操作数,下标为1的 元素是2,2是整型,结果为4

6.这里&a,取出的是整个数组的地址,但是 是地址,大小就为8

7.*&a,这里的*和&之间相互抵消,相当于sizeof(a),所以结果为16

8.&a+1,这里&a取出的是整个数组的地址,+1就是跳过整个数组之后的地址,但是 是地址大小就是8

9.&arr[0],这里arr[0]是首元素,取出首元素的地址,是地址,大小则为8

9.&arr[0]+1,取出首元素的地址+1,得到的第二个元素的地址,是地址 大小则为8


字符数组

sizeof:

题目一:

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.sizeof括号里面单独放数组名,这里的数组名表示整个数组,sizoef计算的是整个数组的的大小,数组有6个元素,都是char类型,所以结果为6*char = 6

2.这里arr+0,arr表示首元素的地址,地址+0还是首元素的地址,是地址 大小则为8

3.这里*arr,arr表示首元素的地址,解引用首元素的地址得到首元素'a',char类型,大小为1

4,arr[1]是数组第二个元素'b',char类型大小为1

5.&arr,取出的是整个数组的地址,但是 是地址,大小则为8

6&arr+1.取出整个数组的地址,+1,得到跳出整个数组后的地址,是地址 大小则为8

7.arr[0]表示首元素,取出首元素的地址,+1得到第二个元素的地址,但是 是地址 大小则为8 

 题目二:

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.sizeof括号里面单独放数组名,数组名表示整个数组,sizeof计算的是整个数组的大小,字符数组里面存储的是'a' 'b' 'c' 'd' 'e' 'f' '\0'这个7个元素,都是char类型,所以结果为7*char = 7

2.arr+0;arr是首元素的地址,+0还是首元素的地址,是地址 大小则为8

3.*arr,解引用首元素的地址得到'a',char类型,大小则为1

4.arr[1]就是‘b',char类型,大小则为1

5.&arr,arr表示整个整个数组,取出数组的地址,是地址 大小则为8

6. &arr+1,取出数组的地址,+1得到跳过整个数组之后的地址,是地址 大小则为8

7.&arr[0]+1,取出首元素的地址,+1,得到第二个元素的地址,是地址 大小则为8

 题目三:

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

运行一下

 

解析

1.p是指针变量,指向的是这个常量字符串的首元素地址,是地址 大小则为8

2.p+1,p是首元素地址,+1得到第二个元素的地址,是地址 大小则为8

3.*p,p是首元素地址,解引用首元素地址得到首元素'a',char类型,大小则为1

4.p[0]和*p一样,与3同理,大小则为1

5.&p,对p取地址,相当于还是获得地址,是地址大小则为8

6.&p+1,地址+1还是得到地址,是地址大小则为8

7.p[0]是首元素,取出首元素的地址,+1得到第二个元素的地址,是地址大小则为8


strlen:

题目一

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	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[0] + 1));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	return 0;
}

运行一下

解析:

1.字符数组里面其实存的是’a'  'b'  'c'  'd'  'e'  ' f ',并没有'\0',而strlen统计的是'\0'之前元素的个数,如果数组里面没有,那就会继续向内存里面找,直到找到'\0\为止,所以结果是个随机值

2.arr是首元素的地址,arr+0还是首元素的地址,所以这个的结果同1,也是个随机值

3.&arr取出的是整个数组的地址,起始位置是数组第一个元素的位置,strlen还是会从第一个元素的位置开始往后读取,所以结果还是随机值

4.&arr+1,取出的是整个数组的地址,+1,得到跳过整个数组后的地址,strlen就会从这个地址往后读取,所以结果也是随机值,但是得到的值会比arr数组得到的值少6

5.&arr[0]+1,取出第一个元素的地址,+1,得到第二个元素的地址,strlen就会从第二个元素开始往后读取,结果会比arr[]得到的值少1

6.strlen需要传地址过去,否则会出错

7.strlen需要传地址过去,否则会出错

 题目二

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[0] + 1));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	return 0;
}

 运行一下

解析

1.字符数组arr里面存储的是’a'  'b'  'c'  'd'  'e'  ' f ' '\0',arr表示首元素的地址,strlen从首元素开始向后读取,读到'\0',strlen是统计'\0'之前的元素个数,所以结果为6

2.arr是首元素地址,+0还是首元素的地址,与1同理,结果为6

3.&arr取出的是整个数组的地址,和首元素的地址相同,所以相当于strlen从首元素开始读取,与1,2同理,结果为6

4.&arr+1;取出整个数组的地址,+1得到跳出整个数组之后的地址,但是内存中的'\0'不知道会在哪里,所以结果是随机值

5.&arr[0]+1,取出首元素的地址,+1,得到第二个元素的地址,所以strlen从第二个元素开始向后读取,结果为5

6.strlen需要传地址过去,否则会出错

7.strlen需要传地址过去,否则会出错

题目三:

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 + 1));
	printf("%d\n", strlen(&p[0] + 1));
	printf("%d\n", strlen(*p));
	printf("%d\n", strlen(p[0]));
	return 0;
}

 运行一下

解析

1.常量字符串默认结束标志为'\0',p是首元素地址,strlen从首元素往后读取,所以结果为6

2.p+1,得到第二个元素的地址,所以strlen从第二个元素往后读取,结果为5

3.&p是取的指针变量p的地址,那么计算就与常量字符串无关了,结果就是随机值,虽然在x64上面显示的是6,但是换成x86就变了。

4&p+1,指针变量p的地址+1,结构还是随机值

5.&p[0]+1,p[0] 等价于*p,是首元素'a’,取出首元素'a'的地址,+1得到第二个元素的地址,

从第二个元素往后读取,与2同理,结果为5

6.strlen需要传地址过去,否则会出错

7.strlen需要传地址过去,否则会出错


二维数组

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

运行一下

解析

1.sizeof括号里面单独放数组名,数组名表示整个数组,sizeof计算的是整个二维数组的大小,结果为3 * 4 * int = 48

2.arr[0][0],就是二维数组第一行第一个元素,为int类型,大小为4

3.这里a[0]是这个二维数组的第一行数组,a[0]就相当于是数组名,那么数组名表示整个数组,大小则为4 * int = 16

4.a[0]表示第一行首元素的地址,+1之后得到第一行第二个元素的地址,是地址大小则为8

5.解引用第一行第二个元素的地址,得到值,为int类型,大小则为4

6.a+1,a表示首元素的地址(也是第一行的地址),+1之后得到第二行的地址,是地址大小则为8

7.*(a+1) == a[1],a[1]是数组名,单独放在sizeof内部,计算的就是第二行整个数组的大小,4个int类型,大小则为4 * int = 16

8.arr[0]是数组名,取出的是第一行整个数组的地址,+1,得到第二行的地址, 是地址 大小则为8

9.*(&a[0]+1) == a[2],数组名单独放在sizoef内部,计算的是这一行整个数组的大小,大小则为16

10.*a == a[0],a[0]是数组名,数组名单独放在sizeof内部,大小则为16

11.a[3]也是数组名,但是他越界了,sizeof只是根据类型判断,所以不会管它是否越界,所以数组名放在sizeof内部,计算的是这一行整个数组的大小,为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;
}

运行一下

解析

1.a是首元素的地址,+1得到第二个元素的地址,解引用之后,得到2

2.&a取出的是整个数组的地址,+1得到跳过整个数组之后的地址,然后把这个地址强制类型转换成int*赋值给ptr,ptr-1之后就是指向5的地址,解引用之后就等到5

题目二

//假设结构体的大小是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;
}

运行一下

解析

1.这里的p是一个结构体指针,结构体+1要跳过一个结构体,这个结构体大小为20,+1,相当于+20个字节,所以结果为00100014,在16进制中1 4表示十进制的20

2.这里p被强制类型转换为无符号的长整型,整型值+1就是+1,+0x1就相当于+1,所以结果为00100001

3.这里p被强制类型转换为int*类型的指针了,int*类型的指针+1,跳过4个字节,所以结果为

00100004

 题目三

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

运行一下

解析

这里数组里面其实时逗号表达式,它是从左到右依次计算,整个表达式的值为最后一个表达式的值,所以其实数组里面存储的是{{1,3},{5,0},{0,0} }。这里p指向的是a[0],带入表示之后相当于打印了a[0][0],就是整个二维数组,第一行第一个元素,就是1。

 题目四

//假设环境是x86环境,程序输出的结果是什么
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;
}

运行一下

解析

地址-地址 == 指针-指针的绝对值 得到的是指针和指针之间的元素个数的

p是数组指针,指向的数组是4个整型元素的

把a的地址赋值给p,p里面只有4个整型元素,p+1只能跳过4个整型元素

中间相差4个元素。

%p是打印地址

所以结果为FFFFFFFC和-4

 题目五

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

运行一下

解析

aa是数组名,取地址aa是取出整个二维数组的地址,所以它+1,得到跳出整个数组之后的地址,在赋值给ptr1,ptr1-1就得到二维数组最后一个元素的地址,解引用就得到10,aa是数组名,是二维数组第一行的地址,+1得到第二行的地址,赋值给ptr2,ptr-2就得到第一行最后一个元素的地址,解引用就得到5

题目六 

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

运行一下

解析

a是指针数组,里面有3个char*类型的指针,a是数组名,是首元素(char*)的地址,把他赋值给了pa,pa++,得到第二个char*类型的指针,解引用之后得到第二个字符串

 题目七

#include <stdio.h>
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;
}

运行一下

解析

根据画图分析

1.我们可以看出cpp指向的是cp数组的首元素,++cpp得到cp数组的第二个元素地址,cp的第二个元素指向的是c数组的第三个元素地址,第一次解引用之后得到第二个元素,指向的是c数组的第三个元素的地址,再解引用之后得到字符串P地址地址,打印结果就为POINT

2.*--*++cpp+3,这么多运算符,怎么算的呢,首先肯定是先算++cpp,cpp在前面已经++了指向的是cp数组的第二个元素的地址,cpp再次++,指向的是cp数组第三个元素的地址,解引用得到(c+1),然后 --(c+1)得到的是cp的第四个元素的地址,解引用得到第四个元素,指向的是c数组的第一个元素的地址,地址+3,跳过三个字节,地址就从E跳到了E,所以后面的打印结果为ER

3.*cpp[-2]+3,cpp在之前的两次++之后,指向的是cp数组的第三个元素,cpp[-2] == *(cpp-2),解引用之后得到cp数组的第一个元素,在解应用得到的是c数组的第四个元素,第四个元素指向的是F的地址,+3之后,得到的就是S的地址,打印结果就是ST

4.cpp[-1][-1]+1,这里的cpp[-1][-1] == *(*(cpp-1)-1),解引用*(cpp-1)得到cp数组的第二个元素,指向的是c数组的第三个元素的地址,在*(第三个元素的地址-1),得到第二个元素,指向N的地址,+1,得到指向E的地址,打印出来就是EW

+和-不会改变它本身的值,但是++和--会影响它本身的值

例如:

a = 5; a+3之后a的值还是5,但是a++之后a的值就变成6了

  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值