说到C语言,可能大多数人会想到指针,并且大多数人也会因为指针从C语言入门到入土。所以可以毫不夸张的说,学好了C语言的指针也就学好了C语言。
那么今天我要分享的是指针与数组相结合的题目与相关知识。希望能够对大家有帮助。
首先我们先看下面的一组题目:
一维数组
#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; }
大家觉得上面题目的答案会是什么呢?
我们想要做对这种类型的题,关键就在于我们是否能够知道数组名a在不同的地方代表的是什么意思。那么在这里我给大家分享一个小技巧:数组名只要单独放在sizeof内部,就像这样sizeof(a),这里的a就代表的是整个数组,sizeof(a)计算的是整个数组的大小。除此之外,数组名所表示的意思都是数组首元素的地址,在知道了这个技巧了之后,我们再看看上面的题目是不是觉得就很简单了呢?
我这里是在32位的环境下测试的,地址的大小是4个字节,准确一点来说其实答案是这样的:
16 4/8 4 4/8 4 4/8 16 4 4 4,看看是不是和你想得有些许差别呢?别急,这里我来给大家说说容易犯错误的地方:第一个sizeof(a),a单独放在sizeof内部,说明他计算的是整个数组的大小。而第二个sizeof(a+0),这里的a代表的是数组首元素地址,a+0之后还是数组首元素的地址,地址的大小在32位环境中是4个字节,在64位环境中占8个字节。第三个sizeof(*a),这里还是代表首元素地址,解引用之后就得到首元素的内容‘1’,而1又是整形类型,所以计算的大小是4个字节。后面的原理也大概相同,我在这里就不过多解释了,你们下去可以自行琢磨琢磨。
掌握了上面的内容后,我们再来看一组
字符数组
#include<stdio.h> #include<string.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)); 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; }
这些题呢?你是否依然能做对呢?
想要做对这些题,我们还需要了解{'a','b','c','d','e','f'}与"abcdef"的区别。{'a','b','c','d','e','f'}里面包含
'a' 'b' 'c' 'd' 'e' 'f'这些字符,而"abcdef"里面包含'a' 'b' 'c' 'd' 'e' 'f' '\0'。看出来区别了吗,{}里面不含有'\0',而""里面则含有'\0',所以我们在做题的时候需要额外的注意这些点。不仅如此,不知道你们是否也发现了我上面使用的计算数组元素个数所使用的工具也不一样,一个是sizeof,一个是strlen,那么这两个有什么区别呢?sizeof是你数组中有多少个元素n,就返回无符号整型n,而strlen则是从你给的地址开始计数,知道遇到'\0'。所以上面的答案也就是。
不对啊,答案对不对我们先不说,按理来说,屏幕上不是应该打印14个数字吗?怎么才9个数字呢?我们来看看第十个strlen(*arr),arr代表的是首元素的地址,而解引用的话就得到了第一个元素'a',对照ASCII表,我们可以将'a'转换为97,所以这里就相当于strlen(97),我们看看strlen的参数
strlen的参数是地址啊,但是我们传进去的是数字该怎么搞啊。这里97将会被转换为地址即0x000061,而这个地址又不一定在数组中,所以就导致了非法访问,这就很危险了,所以我们还是得多注意点。
是不是这些很有意思呢?我们继续看一组:
#include<stdio.h> #include<string.h> 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)); 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)); //这里&arr+1跳过的是整个数组 printf("%d\n",strlen(&arr[0]+1)); return 0; }
这里我就不做过多的解释了,紧跟着下面图片的答案是error,error,6,随机值,5
接下来就给大家上点难度了。
二维数组
#include<stdio.h> #include<string.h> 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; }
答案是什么呢?是不是感觉有点懵啊,别着急,其实二维数组跟一维数组是一个原理,只是有点点的差异。sizeof(a)计算的也还是整个数组的大小,而除了a单独放在sizeof内部之外,a还是代表的首元素地址,只是这里的首元素地址与一维数组的有点差异,二维数组的首元素地址代表的是第一行数组的地址,a[0]和a+0代表第一行首元素地址,a[1]和a+1代表的是第二行首元素的地址,我们也可以这样看,当a[i]或a+i单独放在sizeof内部是还是相当于计算的第i+1行的所有元素。这样上面的题目是不是也迎刃而解了呢?看看答案是不是跟你的一样呢?
总结
数组名的意义:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3.除此之外所有的数组名都表示首元素的地址。
好了这些就是我今天分享的全部内容了,谢谢大家的观看