1. sizeof和strlen的对比
1.1 sizeof
在学习操作符的时候,我们学习了sizeof , sizeof 计算变量所占内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的大小。
1.2 strlen
strlen 是C语言库函数,功能是求字符串长度。函数原型如下:
size_t strlen ( const char * str );
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \\0 之前字符串中字符的个数。 strlen 函数会⼀直向后找 \\0 字符,直到找到为止,所以可能存在越界查找。
2. 数组和指针笔试题解析
分析之前先给出特例
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表⽰整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
例题1
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\\n", sizeof(a));//4*4=16
printf("%d\\n", sizeof(a + 0));//a+0首元素的地址 4/8
printf("%d\\n", sizeof(*a));//a[0] 4
printf("%d\\n", sizeof(a + 1));//a+1是a[1]的地址 4/8
printf("%d\\n", sizeof(a[1]));//4
printf("%d\\n", sizeof(&a));//整个数组的地址 4/8
printf("%d\\n", sizeof(*&a));//&a是整个数组的地址,解引用返回整个数组,等价sizeof(a)=16
printf("%d\\n", sizeof(&a + 1));//跳过数组的地址,还是地址 4/8
printf("%d\\n", sizeof(&a[0]));//首元素地址 4/8
printf("%d\\n", sizeof(&a[0] + 1));//a[1]的地址 4/8
return 0;
}
例题2
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\\n", sizeof(arr));// 6*1=6
printf("%d\\n", sizeof(arr + 0));// arr[0]的地址 4/8
printf("%d\\n", sizeof(*arr));// arr[0] 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));//arr[1]的地址 4/8
return 0;
}
例题3
//size_t strlen ( const char * str );函数原型
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\\n", strlen(arr));//arr[0]地址 无\\0 strlen无法识别 随机值
printf("%d\\n", strlen(arr + 0));//arr[0]地址 无\\0 strlen无法识别 随机值
printf("%d\\n", strlen(*arr));//'a'==97 从97这个地址开始找\\0 97这个位置是野指针,导致程序崩溃
printf("%d\\n", strlen(arr[1]));//'b'==98 同上
printf("%d\\n", strlen(&arr));//&arr是整个数组地址,但数值更arr地址一样,所以还是随机值
printf("%d\\n", strlen(&arr + 1));//跳过数组的地址,随机值
printf("%d\\n", strlen(&arr[0] + 1));//arr[1]地址,随机值
例题4
char arr[] = "abcdef";
printf("%d\\n", sizeof(arr));//abcdef\\0 7
printf("%d\\n", sizeof(arr + 0));//arr[0]的地址 4/8
printf("%d\\n", sizeof(*arr));//arr[0] 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
例题5
char arr[] = "abcdef";
printf("%d\\n", strlen(arr));//abcdef\\0 6
printf("%d\\n", strlen(arr + 0));//arr[0]地址,同上
printf("%d\\n", strlen(*arr));//arr[0]崩溃
printf("%d\\n", strlen(arr[1]));//同上
printf("%d\\n", strlen(&arr));//6
printf("%d\\n", strlen(&arr + 1));//随机值
printf("%d\\n", strlen(&arr[0] + 1));//5
例题6
char* p = "abcdef";//p是a的地址
printf("%d\\n", sizeof(p));// 4/8
printf("%d\\n", sizeof(p + 1));//p+1是地址 4/8
printf("%d\\n", sizeof(*p));//*p=='a' 1
printf("%d\\n", sizeof(p[0]));//p[0] == *(p+0)=='a' 1
printf("%d\\n", sizeof(&p));//p的地址(二级指针) 4/8
printf("%d\\n", sizeof(&p + 1));// 4/8
printf("%d\\n", sizeof(&p[0] + 1));//b的地址,4/8
例题7
char* p = "abcdef";
printf("%d\\n", strlen(p));//6
printf("%d\\n", strlen(p + 1));//5
printf("%d\\n", strlen(*p));//*p=='a' 崩溃
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));//b的地址 5
例题8
int a[3][4] = { 0 };
printf("%d\\n", sizeof(a));//12*4==48
printf("%d\\n", sizeof(a[0][0]));//4
printf("%d\\n", sizeof(a[0]));//可以理解为第一行的数组名 4*4==16
printf("%d\\n", sizeof(a[0] + 1));//&a[0][1] 4/8
printf("%d\\n", sizeof(*(a[0] + 1)));//a[0][1] 4
printf("%d\\n", sizeof(a + 1));//a理解为第一行数组的地址,a+1跳到第二行的地址 a的类型int(*)[4]
printf("%d\\n", sizeof(*(a + 1)));//第二行的数组 16
printf("%d\\n", sizeof(&a[0] + 1));//第二行数组的地址 4/8
printf("%d\\n", sizeof(*(&a[0] + 1)));//第二行的数组 16
printf("%d\\n", sizeof(*a));//第一行数组 16
printf("%d\\n", sizeof(a[3]));//sizeof只会推到括号里的类型,不会越界 16
3. 指针运算笔试题解析
例题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;
}

如图所示
&a + 1跳过整个数组,再被强制转化成整形指针,再-1,回退到a[4]的地址
答案 : 2 ,5
例题2
//在X86环境下
//结构体的⼤⼩是20个字节
struct Test
{
int Num;//4
char* pcName;//4
short sDate;//2
char cha[2];//2*1==2
short sBa[4];//4*2==8 4+4+2+2+8 == 20
}*p = (struct Test*)0x100000;//0x100000为Test的地址
int main()
{
printf("%p\\n", p + 0x1);//p是一个结构体指针,+1跳过该结构体,20个字节,0x100014
printf("%p\\n", (unsigned long)p + 0x1);//无符号整型+1,0x100001
printf("%p\\n", (unsigned int*)p + 0x1);//unsigned int* 4个字节 0x100004
return 0;
}
答案:00100014
00100001
00100004
例题3
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
注意该题(,),不是{,},“,”的结果是最后一个数
如图

答案:1
例题4
// 假设环境是x86环境,程序输出的结果是啥?
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;
}
如图

这里指针—指针得到的是指针之间的元素个数(由于地址从低到高准确来说是绝对值)
%p打印的是地址,认为-4是一个地址,直接打印
%d整形打印出对应的补码

二进制中4位转化位1位十六进制 ,即1111为15对应F,1100为12对应C
答案: FFFFFFFC,-4
例题5
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;
}

答案:10,5
例题6
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\\n", *pa);
return 0;
}

指针数组分别存w,a,a的地址,pa存a的地址,a表是w的地址,+1表是a的地址
答案:at
例题7
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);//**(cpp-2)+3
printf("%s\\n", cpp[-1][-1] + 1);//*(*(cpp-1)-1)+1
return 0;
}

这种涉及到多级指针的问题画图很重要




答案:POINT
ER
ST
EW



