近几年互联网受疫情影响,许多互联网都使用牛客网在线笔试招人
很多同学因为不熟悉牛客网的环境和使用,最后在线笔试面试中屡屡受挫
牛客网提供了语言巩固,算法提高等在线OJ题,更有面试真题,大厂内推!
链接附上点击链接注册牛客网
牛客网这么好用,但是下面几个关于牛客网的知识你了解过吗?
你知道你OJ过不了,牛客网几种经典的英文报错提示的含义吗?
你知道牛客网的OJ分为IO型和接口型吗?
你使用过牛客网的调试功能吗?
众所周知,指针是C语言的灵魂,很多人就是倒在指针的脚下。今天,我来带大家看一看指针在笔试中是怎么考的吧!(提示:本篇博客测试环境是vs-x64,该环境下指针占8个字节)
练习题1
int main() { int a[4] = { 1,2,3,4 }; printf("%u\n", sizeof(a));//16-sizeof(数组名)-整个数组 printf("%u\n", sizeof(a+0));//8-不是单独的数组名-数组首元素的地址 printf("%u\n", sizeof(*a));//4-数组首元素的地址解引用-数组首元素 printf("%u\n", sizeof(a+1));//8-数组第2个元素的地址 printf("%u\n", sizeof(a[1]));//4-数组第2个元素 printf("%u\n", sizeof(&a));//8-整个数组的地址 printf("%u\n", sizeof(*&a));//16-对整个数组的地址解引用,得到的是整个数组-sizeof(数组名) printf("%u\n", sizeof(&a+1));//8-&a是整个数组的地址,+1跳过一个数组,还是一个数组的地址 printf("%u\n", sizeof(&a[0]));//8-首元素的地址 printf("%u\n", sizeof(&a[0]+1));//8-第2个元素的地址 return 0; }
练习题2
int main() { char str[5] = { 'a','b','c','d','e' }; printf("%d\n", sizeof(str));//5-sizeof(数组名)-整个数组 printf("%d\n", sizeof(str+0));//8-数组首元素的地址 printf("%d\n", sizeof(*str));//1-数组首元素 printf("%d\n", sizeof(str[1]));//1-数组第二个元素 printf("%d\n", sizeof(&str));//8 printf("%d\n", sizeof(&str[0]+1));//8 printf("%d\n", sizeof(str[0]+1));//4-字符和整型相加-整型提升 //等价于printf("%d\n", sizeof('a'+1));//4-整型提升 return 0; }
练习题3
int main() { char str[] = { 'a','b','c','d','e' }; printf("%d\n", strlen(str));//随机值 printf("%d\n", strlen(str+0));//随机值 printf("%d\n", strlen(*str));//strlen('a')-->strlen(97);//野指针 printf("%d\n", strlen(str[1]));//野指针 printf("%d\n", strlen(&str));//随机值 printf("%d\n", strlen(&str+1));//随机值 printf("%d\n", strlen(&str[0]+1));//随机值 return 0; }
这里的第三个printf处如果调试的话,这个错误代表的意思就是访问了非法内存(有一些内存地址是没有办法访问的,有一些是允许访问,但是也会进行一定的检测)
关于sizeof和strlen:
strlen是求字符串长度的,关注的是字符串中的'\0',计算的是\0之前出现字符的个数
strlen是库函数,只针对字符串
sizeof只关注占用内存的大小,不在乎内存中放的是什么
sizeof是操作符
练习题4
int main() { int a[3][4] = { 0 }; printf("%d\n", sizeof(a));//3*4*4=48-整个二维数组 printf("%d\n", sizeof(a[0]));//8错//4*4=16对 sizeof(一维数组数组名)-整个第一个一维数组 printf("%d\n", sizeof(a[0]+1));//8-第2个一维数组的地址 printf("%d\n", sizeof(a[0][0]));//4-第一个一维数组的第1个元素 printf("%d\n", sizeof(*(a[0]+1)));//4-第一个一维数组的第2个元素 printf("%d\n", sizeof(*(a+1)));//8错//4*4=16对 sizeof(一维数组数组名)-整个第2个一维数组 printf("%d\n", sizeof(a+1));//8-第2个一维数组的地址 printf("%d\n", sizeof(&a[0]+1));//8-第一个一维数组的第2个元素 printf("%d\n", sizeof(*a));//4*4=16-整个第一个一维数组 printf("%d\n", sizeof(a[3]));//16-整个第四个一维数组 return 0; }
练习题5
int main() { int a[5] = { 1,2,3,4,5 }; int* ptr = (int*)(&a + 1); printf("%d %d", *(a + 1), *(ptr - 1));//2 5 return 0; }
练习题6
struct Test { int num1; char* num2; short num3; char num4[2]; short num5[4]; }*p; //假设p的值为0x100000,如下表达式的值分别是多少? //已知在当前环境下,Test类型的变量大小是20个字节 //考察:指针/整数+1到底是加了多少 int main() { printf("%p\n", p + 0x1);//0x100014 printf("%p\n", (unsigned long)p + 0x1);//0x100001 printf("%p\n", (unsigned int*)p + 0x1);//0x100004 return 0; }
0x1就是十六进制的1,也就是十进制的1:
对于第一个p+0x1中p是struct Test* 类型的指针,加1,跳过一个sizeof(struct Test)==20,也就是0x00014大小。
同理第二个p是被强制转换为了unsigned long类型,是一个整数,整数=1就是+1,然后按照%p打印出来,加的因为就是1(没有超过16),所以和在原来的0x10000上加1是一样的。
同理第三个p是被强制转换为了unsigned int*类型,加1,加的是4个字节。
练习题7
int main() { int a[4] = { 1,2,3,4 }; int* ptr1 = (int*)(&a + 1); int* ptr2 = (int*)(a + 1); int* ptr3 = (int*)((int)a + 1); int* ptr4 = (int*)((char*)a + 1); printf("%x %x %x %x\n\n", ptr1[-1], *ptr2,*ptr3,*ptr4);// return 0; }
ptr3得到的方式是:
通过将整型指针强制转换为整型数值,然后加1,最后再强制转换为整型指针;
ptr4得到的方式是:
通过将整型指针强制转换为字符指针,然后加1,最后再强制转换为整型指针。
两个的效果是一样的。
练习题8
int main() { int a[3][2] = { (0,1),(2,3),(3,4) };//坑点:逗号表达式 int* p; p = a[0]; printf("%d\n", p[0]); //等价于printf("%d\n", *p); return 0; }
练习题9
int main() { int a[4][5]; int(*p)[3];//重点在于这里的3,不是5 p = a; printf("%p %d\n", &p[3][2] - &a[3][2], &p[3][2] - &a[3][2]); return 0; }
练习10
int main() { int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 }; int* ptr1 = (int*)(&a + 1); int* ptr2 = (*(a + 1)); //等价于int* ptr2 = (int*)(a + 1); printf("%d %d\n", *(ptr1 - 1), *(ptr2 - 1));//10 5 return 0; }
练习11
int main() { char* a[] = { "I will work","at","alibaba" }; char** pa = a; pa++; printf("%s\n", *pa); return 0; }
练习题12
int main() { char* c[] = { "ENTRE","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; }
下面是我自己的理解方式:
[]和*都可以过桥(也就是找到指针所指向的那个目标), cpp[-1]就是指向的*(cpp-1),就是先指针-1(指向发生改变),然后过桥(找到指针指向的那个目标);
然后这里的虚线就是不会有自增++有副作用
a=a+1;有副作用(a变了)
但是a+1;就没有副作用(a没有变