一、指针和数组在C语言里是最重要的知识点之一
1.1对于指针和数组的复习直接以扫题的方式,直接做题,做完对答案!(答案在最后)
题目(1)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.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));
//字符数组
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));
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));
const 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));
//二维数组
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)
//指针和数组题
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16byte// sizeof是操作符,sizeof计算的是类型大小,sizeof(数组名)计算的是整个数组的大小,a有4个元素每个元素是int类型大小所以4*4=16字节
printf("%d\n", sizeof(a + 0));//32位下4byte,64位下8byte
printf("%d\n", sizeof(*a));//4byte
printf("%d\n", sizeof(a + 1));//32位下4byte,64位下8byte
printf("%d\n", sizeof(a[1]));//4byte
printf("%d\n", sizeof(&a));//32位下4byte,64位下8byte
printf("%d\n", sizeof(*&a));//16byte对的//取整个数组的地址解引用得到的是整个数组
printf("%d\n", sizeof(&a + 1));//32位下4byte,64位下8byte
printf("%d\n", sizeof(&a[0]));//32位下4byte,64位下8byte
printf("%d\n", sizeof(&a[0] + 1));//32位下4byte,64位下8byte
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//6byte
printf("%d\n", sizeof(arr + 0));// 4或8 -数组名+0得到的是一个地址,sizof地址32位下位4b,64位下为8b
printf("%d\n", sizeof(*arr));//1byte
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));// 4或8 -取数组的地址,得到的是地址,sizof一个地址32位下是4b,64位下是8b
printf("%d\n", sizeof(&arr + 1));// 4或8
printf("%d\n", sizeof(&arr[0] + 1));// 4或8
printf("%d\n", strlen(arr));//随机值
printf("%d\n", strlen(arr + 0));//随机值
//printf("%d\n", strlen(*arr));//报错 -strlen()是用来计算字符串长度的,传参要传的是字符串的地址//*arr得到的是字符不是地址->相当于strlen('a')->相当于strlen(97)->相当于之直接去访问97这个地址->这块地址不属于你的->非法访问
//printf("%d\n", strlen(arr[1]));//报错 -跟上面一样
//printf("%d\n", strlen(&arr));//报错 -strlen的原型是 size_t strlen(const char* ptr);接收的参数类型是 const char* ,而&arr得到的是整个数组的地址,这个地址的类型是 char(*ptr)[6],与const char*ptr 类型不匹配
//printf("%d\n", strlen(&arr + 1));//报错 -取数组地址+1得到的是跳过整个数组后的地址,这个地址的类型一样是char(*)[6],与strlen函数接收的参数类型不匹配
printf("%d\n", strlen(&arr[0] + 1));//随机值
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7
printf("%d\n", sizeof(arr + 0));//32位下4byte,64位下8byte
printf("%d\n", sizeof(*arr));//1
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));//32位下4byte,64位下8byte
printf("%d\n", sizeof(&arr + 1));//32位下4byte,64位下8byte
printf("%d\n", sizeof(&arr[0] + 1));//32位下4byte,64位下8byte
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr + 0));//6
//printf("%d\n", strlen(*arr));//报错,strlen(传的是地址),*arr得到的是字符'a'->相当于strlen('a')->strlen(97)->非法访问
//printf("%d\n", strlen(arr[1]));//报错,跟上面一样
//printf("%d\n", strlen(&arr));//报错 //&arr得到的是整个数组的地址,类型是char(*)[7],与strlen的接收的参数类型const char*不匹配
//printf("%d\n", strlen(&arr + 1));//报错,与上面类似
printf("%d\n", strlen(&arr[0] + 1));//5
const char* p = "abcdef";
printf("%d\n", sizeof(p));32位下4byte,64位下8byte
printf("%d\n", sizeof(p + 1));//32位下4byte,64位下8byte
printf("%d\n", sizeof(*p));//1
printf("%d\n", sizeof(p[0]));//1
printf("%d\n", sizeof(&p));//32位下4byte,64位下8byte
printf("%d\n", sizeof(&p + 1));//32位下4byte,64位下8byte
printf("%d\n", sizeof(&p[0] + 1));//32位下4byte,64位下8byte
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p + 1));//5
//printf("%d\n", strlen(*p));//报错 - 原因跟上面类似
//printf("%d\n", strlen(p[0]));//报错 -类似
//printf("%d\n", strlen(&p));//报错 -&p得到的是指针p的地址->二级指针与strlen接收的参数类型 const char*不匹配
//printf("%d\n", strlen(&p + 1));//报错 - 跟上面类似
printf("%d\n", strlen(&p[0] + 1));//5 -从b开始往后数
//二维数组
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//48 - 数组名单独放在sizeof里面计算的是整个数组的大小,a是二维数组的数组名,所以计算的是整个二维数组的大小
printf("%d\n", sizeof(a[0][0]));//4 - 第一行第一个元素的大小
printf("%d\n", sizeof(a[0]));//16 - a[0]是第一行的数组名,单独放在sizeof里计算的是第一行的大小
printf("%d\n", sizeof(a[0] + 1));// 4或8 - a[0]是第一行数组名,没有单独放在sizeof里,表示的是第一行的首元素地址,第一行首元素地址+1得到的是第一行第二个元素的地址,只要是地址在32位下大小为4b,在64位下大小为8b
printf("%d\n", sizeof(*(a[0] + 1)));// 4 - a[0]是第一行数组名,没有单独放在sizeof里也没有取地址,表示的是第一行的首元素地址,第一行首元素地址+1得到的是第一行第二个元素的地址,对第一行第二个元素的地址进行解引用得到的是第一行第二个元素本身,sizeof计算的是第一行第二个元素的大小也就是4字节
printf("%d\n", sizeof(a + 1));// 4或8 -a是二维数组名,没有单独放在sizof里也没有取地址,表示的是首元素地址,二维数组首元素地址是第一行的地址,第一行的地址+1得到的是第二行的地址,只要是地址在32位下大小为4b,在64位下大小为8b
printf("%d\n", sizeof(*(a + 1)));// 16 - 对第二行的地址进行解引用得到的是第二行数组 //相当于a[1]
printf("%d\n", sizeof(&a[0] + 1));// 4/8 - 取第一行的地址+1的到的是第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1)));// 16 -对第二行的地址进行解引用的到的是第二行的数组
printf("%d\n", sizeof(*a));//16 - a位二维数组首元素地址也就是第一行地址,对第一行地址解引用得到的是第一行
printf("%d\n", sizeof(a[3]));//16 - a[3]表示第四行的数组名,单独放在sizeof里计算的是整个第四行的大小,sizeof会直接根据类型算出大小
2.1题目(2)
//笔题1
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
//默认小端,x86
int main()
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)((int)a + 1);printf("%x,%x", ptr1[-1], *ptr2);return 0;
}
//笔试题3
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int* p;p = a[0];printf("%d", p[0]);return 0;
}
//笔试题4
int main()
{int a[5][5];int(*p)[4];p = (int(*)[4])a;printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}
三、答案与解析(2)
//笔题1
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1); //取a的地址+1得到的是跳过整个数组后的地址再强转为int*printf("%d,%d", *(a + 1), *(ptr - 1));//数组名首元素地址+1 等于第二个元素地址 ,解引用得到第二个元素,按%d格式打印,第一个打印结果为2 //ptr指向的是跳过整个数组后的地址,因为被强转成int*(按4字节距离访问),ptr-1得到的是前一个地址也就是元素5的地址,对元素5的地址进行解引用并按%d的格式打印,结果为5;return 0;
}
//程序的结果是什么
2 ,5

//笔试题3
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//这里的(0,1)是逗号表达式,结果为最后一个表达式的结果也就是1,(2,3)一样结果为最后一个表达式的结果也就是3,(4,5)结果为5; 实际上相当于int a[3][2]={1,3,5},这样的初始化结果为第一行为1,3,第二行为5,0,第三行为0,0;int* p;p = a[0];//a[0]表示第一行的数组名,即第一行的首元素地址;p=a[0]指针p指向第一行的首元素的地址printf("%d", p[0]);//p[0]相当于*(p+0)也就是解引用第一行首元素的地址即 3return 0;
}
