
经过前面指针基础、指针进阶1、指针进阶2的学习,咱们对指针已经有了深入的理解,那咱们就来看看指针相关的一些笔试题!
看一下下面代码输出都是什么?
#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 + 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;
}咱们可以自己先试着来分析分析。 结果:

解释:
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
//数组名遇见sizeof就是数组元素总大小,即为16(字节)
printf("%d\n", sizeof(a + 0));
//看起来与上一个一样,但是,两者还是有区别:
//单是数组名遇见sizeof的话,就是数组元素总大小;但是这里数组名已经和0进行的算术运算
//即为首元素地址+0,为首元素地址,故输出为4(32位机器)。
printf("%d\n", sizeof(*a));
//数组名为首元素地址,*解引用操作后为4(int型数据),输出为4
printf("%d\n", sizeof(a + 1));
//这个和第二个有点像,首元素地址+1;为第二个元素地址,故大小为4;
printf("%d\n", sizeof(a[1]));
//第二个元素大小,即为4;
printf("%d\n", sizeof(*(a + 1)));
//a + 1数组第二个元素的地址;*(a + 1)数组第二个元素;
//那看起来与a[1]的意思是一样的,其实,a[1]与*(a + 1)是等效的,a[1]是*(a + 1)的简写,
// 故sizeof(*(a + 1))也为4;
printf("%d\n", sizeof(&a));
//&a取出数组的地址,地址即为4(32位);
printf("%d\n", sizeof(*&a));
//*&抵消,和第一个一样,输出为16;
//或者这样思考:&a取出数组的地址,*&a解引用找到数组,sizeof(*&a)计算数组大小;即为16;
printf("%d\n", sizeof(&a + 1));
//&a取出数组地址,&a + 1地址跳过这个数组(对于这个数组跳16个字节)
//但它还是地址,即sizeof(&a + 1)为4(32位);
printf("%d\n", sizeof(&a[0]));
//a[0]为数组首元素,&a[0]首元素地址,sizeof(&a[0])即为地址大小,4(32位)
printf("%d\n", sizeof(&a[0] + 1));
//&a[0]首元素地址,&a[0] + 1首元素地址+1,还是地址,即大小为4(32位机器)
return 0;
}
//主要体会什么叫数组的地址,弄清楚它与首元素地址的区别;看一下下面代码输出都是什么?
#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;
}输出:

解释:
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
//数组名遇见sizeof就为整个数组大小,故为6
printf("%d\n", sizeof(arr + 0));
//同一维数组,数组名在进行算术运算的时候为首元素地址,
//地址为4(32位机器)
printf("%d\n", sizeof(*arr));
//*arr首元素地址*解引用,即为首元素,为1字节
printf("%d\n", sizeof(arr[1]));
//数组第二个元素,大小为1;
printf("%d\n", sizeof(&arr));
//数组地址,为4(32位机器)
printf("%d\n", sizeof(&arr + 1));
//数组地址+1,还是地址,为4(32位机器)
printf("%d\n", sizeof(&arr[0] + 1));
//首元素的地址+1,还是地址,为4(32位机器)
return 0;
}看一下下面代码输出都是什么?
#include<stdio.h>
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));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}介于这两串代码会出现访存错误(不属于你的程序),无法输出,咱们就看可以输出的
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));输出:

解释:
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
//对strlen函数简介:
// 返回类型为字符串大小;
// 参数为字符串地址
// 是用来计算字符串大小的函数,遇到'\0'停止,
printf("%d\n", strlen(arr));
//对于数组arr没有'\0',咱们不知道从首元素地址起哪里有'\0',
//故不知道输出为多少,
printf("%d\n", strlen(arr + 0));
//解释同上;
printf("%d\n", strlen(*arr));
//*arr对首元素地址*解引用,即为首元素,
//它会把'a'(97)当作内存地址去访问,会有意想不到的错误
printf("%d\n", strlen(arr[1]));
//解释同上;
printf("%d\n", strlen(&arr));
//&arr为数组地址,虽然实参类型与形参类型不同,
//但是形参会将实参的类型转化为与自己相同的类型后再在接受,即隐式类型转化;
//故输出与strlen(arr)相同
printf("%d\n", strlen(&arr + 1));
//&arr + 1跳过整个数组之后的地址,之后道理同上虽然传过去的是数组地址,
//但是会发生隐式类型转化,因为跳过了6个元素,故它的输出比上一个少6;
printf("%d\n", strlen(&arr[0] + 1));
//首元素地址+1,故输出比strlen(arr)少1
return 0;
}看一下下面代码输出都是什么?
#include<stdio.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));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}与字符数组2中类似的就不再解释了:
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
//数组名遇见sizeof就为整个数组大小,但是咱们这里要注意
//字符串后面还有一个隐藏的\0呢,所以应该为7,
printf("%d\n", sizeof(arr + 0));//4
printf("%d\n", sizeof(*arr)); //1
printf("%d\n", sizeof(arr[1])); //1
printf("%d\n", sizeof(&arr)); //4
printf("%d\n", sizeof(&arr + 1));//4
printf("%d\n", sizeof(&arr[0] + 1));//4
printf("%d\n", strlen(arr));
//注意:
//strlen遇见\0就停止,即为6
printf("%d\n", strlen(arr + 0));
//6
printf("%d\n", strlen(*arr));
//访问内存失败
printf("%d\n", strlen(arr[1]));
//访问内存失败
printf("%d\n", strlen(&arr));
//6
printf("%d\n", strlen(&arr + 1));
//随机,直到遇到\0
printf("%d\n", strlen(&arr[0] + 1));
//5
return 0;
}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));
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;
}首先,咱们先对char* p = "abcdef"解释一下:
p作为一个字符指针,它需要接收字符的地址 所以这个代码的意思是:将字符串的第一个元素的地址给p
解释:
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));
//p首元素地址,大小为4(32位机器)
printf("%d\n", sizeof(p + 1));
//p + 1第二个元素地址,大小为4(32位机器)
printf("%d\n", sizeof(*p));
//*p首元素地址解引用即为首元素,大小为1
printf("%d\n", sizeof(p[0]));
//p[0]前面说过,相当于*p+0;即与前一个一样,为1;
printf("%d\n", sizeof(&p));
//p为首元素地址,即字符指针,&p则为二级指针,二级指针也是指针呀,大小为4(32位机器)
printf("%d\n", sizeof(&p + 1));
//&p二级指针,&p + 1二级指针跳过一个一级指针(32位机器为4字节),但是它还是地址
//所以为4(32位机器)
printf("%d\n", sizeof(&p[0] + 1));
//p[0]即为a,&p[0]取出首元素地址,&p[0] + 1首元素地址+1,第二个元素地址,大小为4(32位机器)
printf("%d\n", strlen(p));
//传入首元素地址,即求的是字符串长度,为6;
printf("%d\n", strlen(p + 1));
//传入第二个元素地址,即求的是从第二个元素起的字符串长度,为5;
//printf("%d\n", strlen(*p));
//传入首元素,等效于strlen('a')->strlen(98);会导致内存访问错误;
//printf("%d\n", strlen(p[0]));
//同上,内存访问错误
printf("%d\n", strlen(&p));
//&p,二级指针,结果未知
printf("%d\n", strlen(&p + 1));
//同上,结果未知,且两者无联系;
printf("%d\n", strlen(&p[0] + 1));
//&p[0]为首元素地址,&p[0] + 1为第二个元素的地址,
//即求的是从第二个元素起的字符串长度,为5
return 0;
}输出(内存访问错误无输出):

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 main()
{
int a[3][4] = { 0 };
//未完全初始化,默认其他为0;
printf("%d\n", sizeof(a));
//同上,整个数组大小,即为48;
printf("%d\n", sizeof(a[0][0]));
//第0行第0列元素大小,即为4(int);
printf("%d\n", sizeof(a[0]));
//a[0]代表第0行元素,即一维数组,故大小为4*4(int),为16;
printf("%d\n", sizeof(a[0] + 1));
//a[0]进行算数运算时,和一维数组一样,代表第0行数组(一维数组)的首元素(第0个元素)地址,
//a[0] + 1即为第0行第一个元素地址,故大小为4(32位机器);
printf("%d\n", sizeof(*(a[0] + 1)));
//a[0] + 1为第0行第一个元素地址,*解引用即为第0行第一个元素,故大小为4;
printf("%d\n", sizeof(a + 1));
//二维数组数组名为第0行地址(一维数组地址),数组名a + 1即为第1行地址(一维数组地址),
//地址大小为4(32位机器)
printf("%d\n", sizeof(*(a + 1)));
//a + 1为第1行地址,*解引用即为第1行元素,故大小为16;
printf("%d\n", sizeof(&a[0] + 1));
//a[0]表示第0行(即一维数组),&a[0]表示第0行地址,&a[0] + 1即为第1行地址,大小为4(32位机器);
printf("%d\n", sizeof(*(&a[0] + 1)));
//&a[0] + 1为第1行地址,*解引用则为第1行元素,大小为16;
printf("%d\n", sizeof(*a));
//a为首行元素地址(一维数组地址),*解引用即为首行元素,大小为16;
printf("%d\n", sizeof(a[3]));
//很明显,已经越界了,但是sizeof不计算表达式,仅分析类型,因此即使越界也不会报错。
//所以咱们还是来看看,a[3]->*(a+3),同上,还是16;
return 0;
}所以咱们这里可以再进行一次总结:
数组名的意义: