前面我们已经学习了数组,指针初阶和进阶。学了上述知识还没有练习多少题目,接下来就来看看c语言经典指针和数组笔试题解析
#include
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;
}
我们在进行题目练习之前回顾一下基础知识
sizeof()计算的是数据所占空间的大小单位是字节。
数组名代表的是数组首元素的地址,但是有两种情况除外:
- sizeof(数组名) 计算的是整个数组的大小,注意是只有数组名,有其他操作就不是整个数组的大小了。
- &数组名,取出的是整个数组的地址,+1,-1跳过的是整个数组。
地址的大小是4/8,与电脑有关。
题目解析
#include
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16
//sizeof(数组名),计算的是整个数组的大小,
//所以输出值为4*4=16
printf("%d\n", sizeof(a + 0));// 4/8
//sizeof()内部a并不是单独存在的,也没有&
//所以数组名代表的是数组首元素的地址
printf("%d\n", sizeof(*a));//4
//*a中a是数组首元素的地址,*a找到的就是数组首元素
//首元素是整形,大小是4字节
printf("%d\n", sizeof(a + 1));//4/8
//a是数组首元素的地址,a+1是数组第二个元素的地址。
//地址的大小是4/8
printf("%d\n", sizeof(a[1]));//4
//a[1]数组第二个元素,大小4字节。
printf("%d\n", sizeof(&a));
//&a是整个数组的地址,只要是地址大小为4/8
printf("%d\n", sizeof(*&a));//16
//有两种理解方式
//1.&a<-->int (*)[4]
// &a取出的是数组名的地址,类型是int (*)[4],是数组指针
// 数组指针指向的是数组,*&a-->a
//
//2.&和*抵消了,*&a-->a
printf("%d\n", sizeof(&a + 1));// 4/8
//&a取出的是数组的地址,&a<-->int (*)[4]
//&a+1 是从数组a的地址向后跳过了一个(4个整形元素)数组的大小。
//&a+1还是地址,是地址就是4/8字节
printf("%d\n", sizeof(&a[0]));//4/8
//a[0]数组首元素,&a[0]数组首元素的地址
printf("%d\n", sizeof(&a[0] + 1));// 4/8
//&a[0]+1,数组首元素地址+1-->数组第二个元素地址。
return 0;
}
需要补充的知识,strlen是函数,头文件
,是专门获取字符串长度的函数,字符串的结束标志是’\0’,字符数组什么时候出现‘\0’就是strlen函数获取字符串长度的关键。
#include
#include
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;
}
代码解析
#include
#include
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//6
//sizeof(数组名),数组所占空间大小,1*6=6byte
printf("%d\n", sizeof(arr + 0));// 4/8
//arr+0,数组名未单独出现在sizeof内,数组名代表数组首元素地址
//arr+0数组首元素地址
printf("%d\n", sizeof(*arr));// 1
//*arr,对数组首元素地址进行解引用,数组首元素。
//数组首元素是字符型,大小为1byte
printf("%d\n", sizeof(arr[1]));// 1
//数组首元素大小1byte
printf("%d\n", sizeof(&arr));// 4/8
//&arr,取出整个数组的地址,它是地址
//是地址大小为4/8
printf("%d\n", sizeof(&arr + 1));//4/8
//&arr + 1是数组后的地址。
printf("%d\n", sizeof(&arr[0] + 1));//4/8
//&arr[0] + 1是数组第二个元素的地址
printf("%d\n", strlen(arr));//随机值1
//字符数组内'a','b','c','d','e','f'。
//字符数组后面的'\0'还不知道在什么位置。
//所以大小为随机值
printf("%d\n", strlen(arr + 0));///随机值
//arr+0数组首元素的地址,和arr效果一样
//printf("%d\n", strlen(*arr));//报错
//*arr为数组首元素'a',ASCII码为97
//strlen('a')-->strlen(97)
//地址为97的内存是属于系统的,不允许用户使用。
//访问的地址不能预测产生什么效果,*arr可视为野指针
//改代码会报错
//printf("%d\n", strlen(arr[1]));//报错
//a[1]-->'b',
//strlen('b')-->strlen(98)
//产生错误的原因与*a相同
printf("%d\n", strlen(&arr));//随机值1
//&a为整个数组的地址,但是地址访问还是从首元素地址开始
//所以结果也是随机值
printf("%d\n", strlen(&arr + 1)); //随机值1 - 6
//&arr+1,跳过的是整的数组,地址为数组后面的地址
//也为随机值,但是该随机值为随机值1-6
printf("%d\n", strlen(&arr[0] + 1)); //随机值1 - 1
//&arr[0]+1是数组第二个元素的地址,该结果也为随机值
//但是该随机值的为 随机值1-1
return 0;
}
字符串"abcdef",存放在字符数组中,f后默认为’\0’,
strlen是求字符串长度的,关注的是字符串中的\0,计算的是\0之前出现的字符的个数
strlen是库函数,只针对字符串
sizeof只关注占用内存空间的大小,不在乎内存中放的是什么
sizeof是操作符
#include
#include
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;
}
题目解析
#include
#include
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7,数组大小
printf("%d\n", sizeof(arr + 0));//4/8 数组首元素地址大小
printf("%d\n", sizeof(*arr));//1,数组首元素大小
printf("%d\n", sizeof(arr[1]));//1,数组第二个元素大小
printf("%d\n", sizeof(&arr));//4/8,整个数组地址的大小
printf("%d\n", sizeof(&arr + 1));//4/8,数组后面的地址的大小
printf("%d\n", sizeof(&arr[0] + 1));//4/8,数组第二个元素地址的大小
printf("%d\n", strlen(arr));//6,字符串的大小
printf("%d\n", strlen(arr + 0));//6
printf("%d\n", strlen(*arr));//错误,*arr=‘a’;访问地址非法
printf("%d\n", strlen(arr[1]));//错误,arr[1]='b';访问地址非法
printf("%d\n", strlen(&arr));//6,整个数组的地址,得到的也是最低地址处的地址
printf("%d\n", strlen(&arr + 1));//随机值,跳过了整个数组不知道是数组后面的地址
//‘/0’的位置不确定
printf("%d\n", strlen(&arr[0] + 1));//5,指针跳过1个字符型大小的字节
//是第二个元素的地址,计算字符串长度6-1
return 0;
}
需要注意的地方是,char* p = “abcdef”;p是指针变量。 p存储的"abcdef"是字符串首地址,而不是存储的字符串。p+1跳过的是一个字符型所占空间的大小
练习题:
#include
#include
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;
}
题目解析:
#include
#include
int main()
{
char* p = "abcdef";
printf("%d\n", sizeof(p));//4/8,指针变量的大小
printf("%d\n", sizeof(p + 1));//4/8,字符串常量第二个字符地址
printf("%d\n", sizeof(*p));//1,字符串常量首字符的大小
printf("%d\n", sizeof(p[0]));//1,字符串常量首字符的大小
printf("%d\n", sizeof(&p));//4/8,字符指针p的地址
printf("%d\n", sizeof(&p + 1));//4/8,+1跳过一个字符指针的大小,
//但是该空间指向的不确定是谁。
printf("%d\n", sizeof(&p[0] + 1));//4/8,p[0]-->*(p+0)-->*p
//&p[0]+1-->p+1,字符串常量第二个字符地址
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p + 1));//5
printf("%d\n", strlen(*p));//err
printf("%d\n", strlen(p[0]));//err
printf("%d\n", strlen(&p));//随机值,&p是取出指针变量p的地址,
//指针变量p存储的是常量字符串的地址,strlen函数把字符串常量的地址
//看作字符串,这个是一个不确定的值,常量字符串的地址在指针变量中的存储
//是大端存储还是小端存储还是不确定的,所以结果为随机值
printf("%d\n", strlen(&p + 1));//随机值,但是与&p两个随机值没有什么关系
//&p+1是跳过一个指针的大小,指向的该地址与p中不能确定设有'\0'.
//还是谁没有'\0',还是都没有'\0'.
printf("%d\n", strlen(&p[0] + 1));//5,&p[0]+1-->p+1
return 0;
}
需要注意的一些知识
二维数组可以看作是一维数组的数组
数组名代表着首元素的地址,二维数组首元素是一维数组,所以二维数组的的数组名代表第一行一位数组的地址
int a[3][4] = { 0 };sizeof()内部表达式是不进行运算的,只是得到该表达式的数据类型
例题:
#include
#include
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;
}
解析:
#include
#include
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//48
//3*4*4
printf("%d\n", sizeof(a[0][0]));//4
//二维数组第一个整形元素的大小
printf("%d\n", sizeof(a[0]));//16
//a[0],相当于第一行一维数组名,sizeof(a[0])
//是二维数组第一行的大小
printf("%d\n", sizeof(a[0] + 1));//4/8
//a[0], 相当于第一行一维数组名
//a[0]+1,相当于二维数组第一行第二个元素地址
printf("%d\n", sizeof(*(a[0] + 1)));//4
//*(a[0] + 1)-->a[0][1]
//计算的是第一行第二个元素的大小
printf("%d\n", sizeof(a + 1));//4/8
//a+1二维数组第二行元素的地址
printf("%d\n", sizeof(*(a + 1)));//16
//*(a + 1)-->a[1],相当于第二行一维数组名,sizeof(a[1])
//是二维数组第二行的大小
printf("%d\n", sizeof(&a[0] + 1));//4/8
//&a[0]-->&*(a+0)-->a
//&a[0] + 1-->a+1
printf("%d\n", sizeof(*(&a[0] + 1)));//16
//&a[0] + 1-->a+1
//*(&a[0] + 1)-->*(a+1)-->a[1]
//a[1], 相当于第二行一维数组名,sizeof(a[1])
//是二维数组第二行的大小
printf("%d\n", sizeof(*a));//16
//*a-->a[0]是二维数组第一行的地址
printf("%d\n", sizeof(a[3]));//16
//a[3]是二维数组第4行的地址
//虽然二维数组没有第四行,但该代码不是越界
//sizeof()内部表达式是不进行运算的,只是得到该表达式的数据类型
return 0;
}