听说这是目录哦
- 数组和指针笔试题解析🫧
- 一维数组
- 1🍕🍕🍕🍕🍕🍕🍕
- 字符数组
- 1🍔🍔🍔🍔🍔🍔🍔
- 2🌭🌭🌭🌭🌭🌭🌭
- 3🍜🍜🍜🍜🍜🍜🍜
- 4🌮🌮🌮🌮🌮🌮🌮
- 5🍢🍢🍢🍢🍢🍢🍢
- 6🥟🥟🥟🥟🥟🥟🥟
- 二维数组
- 1🧋🧋🧋🧋🧋🧋🧋
- 指针运算笔试题解析🫧
- 1🍒🍒🍒🍒🍒🍒🍒
- 2🍉🍉🍉🍉🍉🍉🍉
- 3🥝🥝🥝🥝🥝🥝🥝
- 4🥥🥥🥥🥥🥥🥥🥥
- 5🍓🍓🍓🍓🍓🍓🍓
- 6🥑🥑🥑🥑🥑🥑🥑
- 7🍊🍊🍊🍊🍊🍊🍊
- 能量站😚
数组和指针笔试题解析🫧
sizeof关注类型,strlen关注内容。
一维数组
1🍕🍕🍕🍕🍕🍕🍕
🍕题:问运行结果是什么
#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;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));//规定sizeof(数组名)计算的是整个数组的大小,而 &数组名 取出的是整个数组的地址,其余情况的数组名都是首元素的地址,一个int型4个字节,答案是4*4=16。printf("%d\n", sizeof(a + 0));//这里的a是数组首地址,首地址加0还是首地址,地址都是4或8字节【x86下是4个字节,x64下是8个字节】,(实际sizeof并不会计算括号内的表达式,它只是推断出表达式结果的类型,根据类型和个数得出结果),这里的答案是4或8。printf("%d\n", sizeof(*a));//这里的a是首地址,解引用后就是首元素,答案是4。printf("%d\n", sizeof(a + 1));//首元素的地址加1就是第二个元素的地址,地址都是4或8【地址都是同样长度的一串字母和数字】,答案是4或8。printf("%d\n", sizeof(a[1]));//第二个元素,一个int型的元素,答案是4。printf("%d\n", sizeof(&a));//整个数组的地址,是地址,答案是4或8。printf("%d\n", sizeof(*&a));//两种解释,第一种是*和&抵消了,最终是sizeof(a)。第二种是&a取出的是整个数组的地址,用*把地址解引用后就是整个数组了。答案是16。printf("%d\n", sizeof(&a + 1));//整个数组的地址加1,跳过整个数组的地址,最终还是地址,答案是4或8。printf("%d\n", sizeof(&a[0]));//第一个元素的地址,答案是4或8。printf("%d\n", sizeof(&a[0] + 1));//第一个元素的地址加1,跳过一个元素,第二个元素的地址,答案是4或8。return 0;
}
字符数组
1🍔🍔🍔🍔🍔🍔🍔
🍔题:问运行结果是什么
#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;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", sizeof(arr));//计算整个数组的大小,6个字符,答案是6printf("%d\n", sizeof(arr + 0));//首元素地址加0,还是首元素地址,答案是4或8printf("%d\n", sizeof(*arr));//首元素地址解引用后是首元素,1个char型的数据,答案是1printf("%d\n", sizeof(arr[1]));//第二个元素,答案是1printf("%d\n", sizeof(&arr));//整个数组的地址,答案是4或8printf("%d\n", sizeof(&arr + 1));//跳过整个数组后的地址,答案是4或8printf("%d\n", sizeof(&arr[0] + 1));//跳过第一个元素后的地址,即第二个元素的地址,答案是4或8return 0;
}
2🌭🌭🌭🌭🌭🌭🌭
🌭题:问运行结果是什么
#include <stdio.h>
#include <string.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;
}
答案与解析(看注释):
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", strlen(arr));//arr是首元素的地址,从首元素开始向后数,没有\0,停不下来,答案是随机值,不同平台的结果不同printf("%d\n", strlen(arr + 0));//首元素加0还是首元素的地址,从首元素开始向后数,没有\0,停不下来,答案是随机值,不同平台的结果不同printf("%d\n", strlen(*arr));//解引用首元素地址后即首元素,括号中应该写地址,所以这个代码是错的printf("%d\n", strlen(arr[1]));//第二个元素,括号中应该写地址,所以这个代码是错的printf("%d\n", strlen(&arr));//整个数组的地址【&arr的类型是char (*)[6],会被强制转换成char*类型,因为strlen是size_t strlen(const char* s)】的值与首元素地址相同,从首元素开始向后数,没有\0,停不下来,答案是随机值,不同平台的结果不同printf("%d\n", strlen(&arr + 1));//跳过整个数组后的地址,从此处往后数,没有\0,停不下来,答案是随机值,不同平台的结果不同printf("%d\n", strlen(&arr[0] + 1));//跳过首元素后的地址,即第二个元素的地址,从此处往后数,没有\0,停不下来,答案是随机值,不同平台的结果不同return 0;
}
3🍜🍜🍜🍜🍜🍜🍜
🍜题:问运行结果是什么
#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));return 0;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{char arr[] = "abcdef";printf("%d\n", sizeof(arr));//计算整个数组的大小,字符串末尾有\0,答案是6+1=7printf("%d\n", sizeof(arr + 0));//首元素地址加1还是首元素地址,答案是4或8printf("%d\n", sizeof(*arr));//首元素解引用后是首元素,答案是1printf("%d\n", sizeof(arr[1]));//第二个元素,答案是1printf("%d\n", sizeof(&arr));//整个数组的地址,答案是4或8printf("%d\n", sizeof(&arr + 1));//跳过整个数组后的地址,答案是4或8printf("%d\n", sizeof(&arr[0] + 1));//跳过首元素后的地址,即第二个元素的地址,答案是4或8return 0;
}
4🌮🌮🌮🌮🌮🌮🌮
🌮 题:问运行结果是什么
#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "abcdef";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 <stdio.h>
#include <string.h>
int main()
{char arr[] = "abcdef";printf("%d\n", strlen(arr));//从首元素开始数,字符串末尾有\0,数到\0前面的停止,答案是6printf("%d\n", strlen(arr + 0));//还是首元素地址,答案是6printf("%d\n", strlen(*arr));//传的是首元素,会报错,应该传地址printf("%d\n", strlen(arr[1]));//传的是第二个元素,会报错printf("%d\n", strlen(&arr));//整个数组的地址,与数组首元素的地址相同【&arr的类型是char(*)[7],会被强制类型转换成char*类型】,即从首元素开始数,字符串末尾有\0,数到\0前面的停止,答案是6printf("%d\n", strlen(&arr + 1));//跳过整个数组后的地址,注意\0属于数组内的,即后面没有\0了,答案是随机值printf("%d\n", strlen(&arr[0] + 1));//从第二个元素开始数,字符串末尾有\0,数到\0前面的停止,答案是5return 0;
}
5🍢🍢🍢🍢🍢🍢🍢
🍢题:问运行结果是什么
#include <stdio.h>
int main()
{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));return 0;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{const char* p = "abcdef";printf("%d\n", sizeof(p));//p是指针,是字符串首字符a的地址,答案4或8printf("%d\n", sizeof(p + 1));//p+1是b的地址,答案是4或8printf("%d\n", sizeof(*p));//p的类型是const char*,*P的类型就是char*,答案是1个字节printf("%d\n", sizeof(p[0]));//可以把常量字符串看成数组,即p[0]是首字符a,也可以理解成p[0] == *(p+0) == *p == 'a',答案是1printf("%d\n", sizeof(&p));//p本来就是地址,再把p的地址取出来,相当于二级指针,即&p的类型是char**,地址都是4或8,答案是4或8printf("%d\n", sizeof(&p + 1));// 跳过p指针变量一个char*大小之后的地址,答案是4或8printf("%d\n", sizeof(&p[0] + 1));//首字符地址再跳过一个char*大小的字节,即b的地址,答案是4或8return 0;
}
6🥟🥟🥟🥟🥟🥟🥟
🥟题:问运行结果是什么
#include <stdio.h>
#include <string.h>
int main()
{char* p = "abcdef";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 <stdio.h>
#include <string.h>
int main()
{char* p = "abcdef";printf("%d\n", strlen(p));//a的地址向后数,答案是6printf("%d\n", strlen(p + 1));//b的地址向后数,答案是5printf("%d\n", strlen(*p));//字符a,会报错printf("%d\n", strlen(p[0]));//一样,字符a,会报错printf("%d\n", strlen(&p));//从p这个指针变量的起始位置开始向后数,p的地址是一块空间,字符串"abcdef"的地址是另一块空间,p的地址未知,也不知道有没有\0,答案是随机值printf("%d\n", strlen(&p + 1));//跳过p的地址后延续的地址,往后数不知道有没有\0,答案是随机值printf("%d\n", strlen(&p[0] + 1));//&p[0]是a的地址,+1后是b的地址,向后数,答案是5return 0;
}
二维数组
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
1🧋🧋🧋🧋🧋🧋🧋
🧋题:问运行结果是什么
#include <stdio.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内就是计算整个的大小。
#include <stdio.h>
int main()
{int a[3][4] = { 0 };printf("%d\n", sizeof(a));//数组名a单独放在sizeof里,计算整个数组的大小,答案是3*4*4=48printf("%d\n", sizeof(a[0][0]));//第一行第一个元素,答案是4printf("%d\n", sizeof(a[0]));//第一行的数组名单独放在sizeof里,计算第一行的总大小,答案是4*4=16printf("%d\n", sizeof(a[0] + 1));//a[0]没有单独放在sizeof里,所以这里的a[0]其实是第一行a[0]的首元素地址,即&a[0][0],+1就是&a[0][1],答案是4或8printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)是第一行的第二个元素,答案是4printf("%d\n", sizeof(a + 1));//这里的a是二维数组a的首元素地址,即第一行地址,a+1跳过一行,是第二个行的地址,二维数组的每个元素是一行,a+1是数组指针,答案是4或8printf("%d\n", sizeof(*(a + 1)));//第二行元素,答案是4*4=16printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,+1后是第二行的地址,答案是4或8printf("%d\n", sizeof(*(&a[0] + 1)));//第二行的元素,答案是4*4=16printf("%d\n", sizeof(*a));//a是二维数组首元素地址,a是第一行的地址,*a是第一行元素,答案是4*4=16printf("%d\n", sizeof(a[3]));//可以通过类型推断出长度,a[3]无需真实存在,a[3]是第四行的数组名,单独放在sizeof里,计算第四行的大小,答案是4*4=16return 0;
}
指针运算笔试题解析🫧
1🍒🍒🍒🍒🍒🍒🍒
🍒题:问运行结果是什么
#include <stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));//a是首元素的地址,+1后就是第二个元素的地址,即2。&a取出的是整个数组的地址,+1就是跳过整个数组后的地址【在5后面】,再-1回到5。答案是2,5
return 0;
}
2🍉🍉🍉🍉🍉🍉🍉
🍉题:问运行结果是什么
#include <stdio.h>
//在X86环境下
//假设结构体的大小是20个字节
//程序输出的结果是啥?
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}
答案与解析(看注释):
#include <stdio.h>
//在X86环境下
//假设结构体的大小是20个字节
//程序输出的结果是啥?
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;//0x100000默认为int型,强制转换为struct Test*型
int main()
{printf("%p\n", p + 0x1);//0x1其实就是1,即p+1,+1就是跳过一个p大小的空间,答案是0x100000+20=00100014【1*16¹+4*16⁰=20】printf("%p\n", (unsigned long)p + 0x1);//整型相加直接加,答案是0x100000+1=0x100001,打印出来是00100001printf("%p\n", (unsigned int*)p + 0x1);//一个unsigned int*是4个字节,答案是0x100000+4=0x100004,打印出来是00100004【在32位环境下用%p打印前面要补够两个0才变成8个16进制位】return 0;
}
运行截图:
3🥝🥝🥝🥝🥝🥝🥝
🥝题:问运行结果是什么
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int* p;p = a[0];printf("%d", p[0]);return 0;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//初始化应用{},所以这里是逗号表达式,结果是最后一个表达式的结果,即a[3][2] = { 1, 3, 5 },即 a[3][2] = { (1, 3), (5, 0), (0, 0) }int* p;p = a[0];//a[0]是第一行的数组名,这里不是前面讲的那两种特殊情况,则这里的a[0]是第一行的首元素,即&a[0][0]printf("%d", p[0]);//p[0] == *(p+0) == *p,即 1return 0;
}
运行截图:
4🥥🥥🥥🥥🥥🥥🥥
🥥题:问运行结果是什么
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}
答案与解析(看注释):
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{+int a[5][5];int(*p)[4];p = a;//把a的地址赋值给pprintf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//p只是指向和a一样的初始地址,但p有自己的类型int (*)[4],所以p[4][2]跳过4个整型和2个字节。a[4][2]跳过5个整型和5个字节。%p是十六进制打印地址,直接把补码转成地址形式。%d打印有符号整型,要把补码转成原码再打印。指针减指针后的绝对值是指针之间的元素个数。return 0;
}
运行截图:
5🍓🍓🍓🍓🍓🍓🍓
🍓题:问运行结果是什么
#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int* ptr1 = (int*)(&aa + 1);int* ptr2 = (int*)(*(aa + 1));printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int* ptr1 = (int*)(&aa + 1);//&aa取出整个数组的地址,+1跳过整个数组,由int (*)[2][5]类型强制转为int (*)int* ptr2 = (int*)(*(aa + 1));//这里的aa是aa的首元素地址,即第一行aa[0],+1后跳过一行,就是第二行首元素的地址,即aa[1][0]==6,本来就是int (*),所以这里的强制转换是迷惑人的printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//ptr1和ptr2的类型都是int (*)类型,指针跳过几个字节由指针的类型决定return 0;
}
运行截图:
6🥑🥑🥑🥑🥑🥑🥑
🥑题:问运行结果是什么
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" };//a是一个指针数组,里面存放的是指针,字符串存的是首字符的地址,分别是w,a,achar** pa = a;//a是首元素的地址,指向"work"pa++;printf("%s\n", *pa);//%s打印字符串,从这个地址向后打印直到\0return 0;
}
运行截图:
7🍊🍊🍊🍊🍊🍊🍊
🍊题:问运行结果是什么
#include <stdio.h>
int main()
{
char *c[] = {"ENTER","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;
}
答案与解析(看注释):
#include <stdio.h>
int main()
{char* c[] = { "ENTER","NEW","POINT","FIRST" };char** cp[] = { c + 3,c + 2,c + 1,c };char*** cpp = cp;//二级指针里存放的是一级指针的地址printf("%s\n", **++cpp);//先++,再*,再*。cpp指向c+3的地址,++后来到c+2,*(c+2)后得到P的地址,再*后就是%S向后打印出POINTprintf("%s\n", *-- * ++cpp + 3);//加法的优先级最低。上一个printf时,cpp以及变成了c+2,现在再++就变成c+1了,*后得到c+1【二级指针里存放的是一级指针的地址,解引用得到存放的内容】,c+1被--后得到c【是cp[2]的内容变成了c,不是变成了cp[3]】,解引用得到c的内容,即字符串ENTER的首字符地址,即E的地址,再+3后就得到第二个E的地址,向后打印ERprintf("%s\n", *cpp[-2] + 3);//*cpp[-2]+3 == **(cpp-2)+3,cpp本来指向了cp[2],-2后指向cp[0],**(cpp-2)+3 == *cp[0]+3 == F地址+3 == S地址,向后打印STprintf("%s\n", cpp[-1][-1] + 1);//cpp还是cp[2],因为只有++和--会改变cpp,上面的cpp[-2]不会。cpp[-1][-1]+1 == *(*(cpp-1)+1) == *(c+2 - 1)+1 == *(c+1)+1 == NEW中N的地址+1 == NEW中E的地址,向后打印EWreturn 0;
}
💗💗💗
💗💗💗
运行截图:
能量站😚
当你弱小的时候,连愤怒都像在撒娇。
❤️❤️❤️ 恭喜! 恭喜! 闯关成功! ❤️❤️❤️