第15讲:深⼊理解指针(5)
⽬录
1. sizeof和strlen的对⽐
2. 数组和指针笔试题解析
3. 指针运算笔试题解析
正⽂开始
1.sizeof和strlen的对⽐
1.1 sizeof
在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存空间的⼤⼩,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。
sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
⽐如:
#inculde <stdio.h>
int main()
{
int a = 10;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
printf("%d\n", sizeof(int));
return 0;
}
输出结果:
1.2 strlen
strlen是C语言库函数,功能是求字符串长度。函数原型如下:
size_t strlen (const char * str);
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。
int main()
{
char arr1[3] = { 'a', 'b', 'c' };
char arr2[] = "abc";
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
printf("%d\n", sizeof(arr1));
printf("%d\n", sizeof(arr2));
return 0;
}
运行结果:
1.3 sizeof 和 strlen的对⽐
sizeof:
1.sizeof是操作符;
2.sizeof计算所占内存空间的大小,单位是字节;
3.不关注内存中存放什么数据。
strlen:
1.strlen是库函数,使用需要包含头文件string.h;
2.strlen是求字符串长度的,统计的是\0之前字符的个数;
3.关注内存中是否有\0,如果没有\0,就会持续往后找,可能会越界。
2.数组和指针笔试题解析
2.1一维数组
#include <stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
//数组名a单独放在sizeof内部,a表示整个数组,计算的是整个数组的大小,单位是字节,四个整型所占内存空间大小:16
printf("%d\n", sizeof(a + 0));
//数组名a与+0一块放在sizeof内部,a仅表示首元素地址,计算的是首元素地址+0,仍然是首元素的地址
// sizeof计算地址的大小,结果是4/8(X86是32位环境,结果是4;X64是64位环境,结果是8.)
printf("%d\n", sizeof(*a));
//这里的a是数组名表示首元素的地址,数组a的首元素为1,整型,所占内存空间大小:4
//*a = *(a + 0) = a[0]
printf("%d\n", sizeof(a + 1));
// 4/8
printf("%d\n", sizeof(a[1]));
// 4
printf("%d\n", sizeof(&a));
// 4/8
printf("%d\n", 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));
// 4/8
return 0;
}
运行结果:
2.2字符数组
代码1:
char arr[] = { 'a', 'b','c', 'd', 'e', 'f' };
printf("%zd\n", sizeof(arr));// 6
printf("%zd\n", sizeof(arr + 0));// arr此时是首元素地址 +0 ,还是首元素地址,输出4/8
printf("%zd\n", sizeof(*arr));// *arr是第一个元素‘a’,因此其所占内存空间为1;
printf("%zd\n", sizeof(arr[1]));//arr[1]是第2个元素‘b’,因此结果是1;
printf("%zd\n", sizeof(&arr));//&arr是整个数组的地址,结果是4/8;
printf("%zd\n", sizeof(&arr + 1));//整个数组的地址再加1,结果是一个地址,所以是4/8
printf("%zd\n", sizeof(&arr[0] + 1));//第一个元素的地址加1,结果是第二个元素的地址,所以是4/8;
运行结果:
代码2:
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));
运行结果:
代码3:
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));
运行结果:
代码4:
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));
运行结果:
代码5:
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));
运行结果:
代码6:
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));
运行结果:
2.3 二维数组
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]));
运行结果:
数组名的意义:
- sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。
- &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表⽰⾸元素的地址。
3.指针运算笔试题解析
3.1题目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;
}
//程序的结果是什么?
3.2题目2:
//在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;
}
题目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;
}
题目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;
}
题目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;
}
题目6:
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 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;
}
本节完