指针 (六):sizeof和strlen细节强化之“做题篇”
目录
1. sizeof和strlen的对比
1.1 sizeof
1.2 strlen
1.3 sizeof 和 strlen的对比
2. 数组和指针笔试题解析
2.1 ⼀维数组
2.2 字符数组
代码1:
代码2:
代码3:
代码4:
代码5:
代码6:
2.3 二维数组
3. 指针运算笔试题解析
3.1 题目1:
3.2 题目2
3.3 题目3
3.4 题目4
3.5 题目5
3.6 题目6
3.7 题目7
1. sizeof和strlen的对比
1.1 sizeof
学习操作符的时,就学习了 sizeof , sizeof是计算变量所占内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小sizeof 只关注占⽤内存空间的大小,不在乎内存中存放什么数据。
观察示例:
//sizeof
int main()
{int a = 0;printf("%zu\n", sizeof(a));printf("%zu\n", sizeof a);//变量名可去掉()printf("%zu\n", sizeof(int));printf("%zu\n", sizeof(a+3.14));//int转换double 8return 0;
}
当sizeof后接一个变量名时,可以去掉(),但类型:int...就不可以
sizeof的返回值是size_t类型的,要用%zu替换打印
1.2 strlen
strlen 是C语⾔库函数,功能是求字符串⻓度。
函数原型如下:size_t strlen ( const char * str );统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找使用时需包含string.h头文件
观察示例:
//strlen
//包含string.h
#include <string.h>int main()
{char arr[] = "hello";// h e l l o \0//strlen统计\0之前字符串字符的个数printf("%zu\n", strlen(arr));//5char arr2[] = { 'a','b','c' };printf("%zu\n", strlen(arr2));//结果未知,随机值//因为这样定义字符数组,是不包含\0的return 0;
}
1.3 sizeof 和 strlen的对比
sizeof :
1. sizeof是操作符2. sizeof计算操作数所占内存的大小,单位是字节3. 不关注内存中存放什么数据
strlen:
1. strlen是库函数,使⽤需要包含头⽂件 string.h2. srtlen是求字符串⻓度的,统计的是 \0 之前字符的个数3. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界
2. 数组和指针笔试题解析
核心知识点,做下面题目必备
数组名的意义:
1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。3. 除此之外所有的数组名都表⽰⾸元素的地址。
2.1 ⼀维数组
题目1:
int a[] = {1,2,3,4};1printf("%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));
解析见下:
//数组和指针笔试题
//x64
// 一维数组
int main()
{int a[] = { 1,2,3,4 };printf("%zu\n", sizeof(a));//16printf("%zu\n", sizeof(a + 0));//8 地址printf("%zu\n", sizeof(*a));//4 首元素printf("%zu\n", sizeof(a + 1));//8 第二个元素的地址printf("%zu\n", sizeof(a[1]));//4printf("%zu\n", sizeof(&a));//8 取出的是数组的地址//&a的特殊性体现在加减整数 是以整个数组地址为单位的//&a的类型 int (*)[4] 数组指针printf("%zu\n", sizeof(*&a));//16 数组指针解引用得到的是数组printf("%zu\n", sizeof(&a + 1));//8printf("%zu\n", sizeof(&a[0]));//8printf("%zu\n", sizeof(&a[0] + 1));//8return 0;
}
2.2 字符数组
代码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;}
答案见下:
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%zu\n", sizeof(arr));// 6//数组名单独放在sizeof中表示整个数组printf("%zu\n", sizeof(arr + 0));// 8printf("%zu\n", sizeof(*arr));//1 首元素printf("%zu\n", sizeof(arr[1]));//1printf("%zu\n", sizeof(&arr));//8printf("%zu\n", sizeof(&arr + 1));//8printf("%zu\n", sizeof(&arr[0] + 1));//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;}
答案见下:
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%zu\n", strlen(arr));//随机值!字符串中没有\0printf("%zu\n", strlen(arr + 0));//还是数组首元素地址!随机值printf("%zu\n", strlen(*arr));//非法访问内存//*arr是首元素 a的asc码值为97 从97开始计数printf("%zu\n", strlen(arr[1]));//同理 非法printf("%zu\n", strlen(&arr));//随机值 等同于arrprintf("%zu\n", strlen(&arr + 1));//随机值 但比上一个少6printf("%zu\n", strlen(&arr[0] + 1));//随机值 但比arr少1return 0;
}
注意:
这样的字符数组后面没有\0,统计起来是随机数
*数组名,以这道题目为例,就是从首元素的asc码值开始统计的,这样就非法访问内存了
代码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;}
答案见下:
//x64
int main()
{char arr[] = "abcdef";printf("%d\n", sizeof(arr));// 7printf("%d\n", sizeof(arr + 0));//8printf("%d\n", sizeof(*arr));//1printf("%d\n", sizeof(arr[1]));// 1printf("%d\n", sizeof(&arr));//8printf("%d\n", sizeof(&arr + 1));//8printf("%d\n", sizeof(&arr[0] + 1));//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;}
答案见下:
int main() {char arr[] = "abcdef";printf("%zu\n", strlen(arr));//6 \0之前的元素个数printf("%zu\n", strlen(arr + 0));//6printf("%zu\n", strlen(*arr));//非法访问可能崩溃 从97开始找printf("%zu\n", strlen(arr[1]));//非法访问可能崩溃 同理printf("%zu\n", strlen(&arr));//6printf("%zu\n", strlen(&arr + 1));//随机值printf("%zu\n", strlen(&arr[0] + 1));//5return 0; }
代码5:
#include <stdio.h>int main(){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;}
答案见下:
//x64
int main()
{char* p = "abcdef";//p中存放的是a的地址//这里就不存在数组的概念了!printf("%zu\n", sizeof(p));//8printf("%zu\n", sizeof(p + 1));//8 b的地址printf("%zu\n", sizeof(*p));//1printf("%zu\n", sizeof(p[0]));//1 *(p+0)printf("%zu\n", sizeof(&p));//8printf("%zu\n", sizeof(&p + 1));//8printf("%zu\n", sizeof(&p[0] + 1));//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;}
答案见下:
int main()
{char* p = "abcdef";printf("%d\n", strlen(p));//6printf("%d\n", strlen(p + 1));//5printf("%d\n", strlen(*p));//errprintf("%d\n", strlen(p[0]));//errprintf("%d\n", strlen(&p));//随机值printf("%d\n", strlen(&p + 1));//随机值printf("%d\n", strlen(&p[0] + 1));//5return 0;
}
2.3 二维数组
题目:
#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;}
答案见下:
//二维数组
int main()
{int a[3][4] = { 0 };printf("%zu\n", sizeof(a));//48 数组名printf("%zu\n", sizeof(a[0][0]));//4printf("%zu\n", sizeof(a[0]));//16 第一行数组的数组名printf("%zu\n", sizeof(a[0] + 1));//8//a[0]是第一行第一个元素的地址,是地址!//a[0]+1是第一行第二个元素的地址printf("%zu\n", sizeof(*(a[0] + 1)));//4 第一行第二个元素printf("%zu\n", sizeof(a + 1));//8//第二行的地址! //a没有单独放在sizeof中,不表示二维数组的地址,即首元素第一行的地址printf("%zu\n", sizeof(*(a + 1)));//16//*(a+1) == a[1],第二行的数组名printf("%zu\n", sizeof(&a[0] + 1));//8//a[0]是第一行的地址//&a[0]取出的是第一行的地址,即第二行的地址printf("%zu\n", sizeof(*(&a[0] + 1)));//16 第二行printf("%zu\n", sizeof(*a));//16//a是首元素地址,就是第一行的地址printf("%zu\n", sizeof(a[3]));//16//sizeof计算大小时,是通过类型来推导计算的return 0;
}
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;}
答案见下:
//指针运算笔试题
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1);//ptr是紧接着下一个数组的地址,并把类型转换为int*//强制类型转换是临时的!printf("%d,%d", *(a + 1), *(ptr - 1));//2 5return 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;}
太可怕了,直接一个结构体,看懵了直接,笑死哈哈哈哈哈
答案见下:
struct Test
{int Num;char* pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000; int main()
{//打印地址 x86 16进制 打印32/4 = 8位printf("%p\n", p + 0x1);//结构体指针 ➕1跳过20个字节//0x00100014printf("%p\n", (unsigned long)p + 0x1);//转换成整数// 0x00100001printf("%p\n", (unsigned int*)p + 0x1);//0x00100004 //32位环境下,指针加1其实是加4,所以0x00100004return 0;
}
具体的解释都包含在里面喽!
3.3 题目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;}
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//{1,3,5}int* p;p = a[0];printf("%d", p[0]);//1return 0;
}
3.4 题目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;}
答案见下:
留意注释哦~
#include <stdio.h>//假设环境是x86环境
int main()
{int a[5][5];int(*p)[4];//p = a;//a是首元素的地址也是第一行的地址 int(*a)[5] //注意:指针的类型!printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//p[4][2]是第18个元素 a[4][2]是第22个元素的地址//-4//%d - 按照十进制的形式 打印有符号的整数 //%d - 认为内存中存放的是有符号证书的补码//%p - 认为内存中存放的补码就是地址 以十六进制//10000000 00000000 00000000 00000100//11111111 11111111 11111111 11111011//11111111 11111111 11111111 11111100//FF FF FF FCreturn 0;
}
3.5 题目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;}
答案见下:
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));//10 5return 0;
}
3.6 题目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" };char** pa = a;pa++;printf("%s\n", *pa);//at//%s从起始位置开始向后打印字符串return 0;
}
3.7 题目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;}
答案见下:
int main()
{char* c[] = { "ENTER","NEW","POINT","FIRST" };char** cp[] = { c + 3,c + 2,c + 1,c };char*** cpp = cp;printf("%s\n", **++cpp);//pointprintf("%s\n", *-- * ++cpp + 3);//ERprintf("%s\n", *cpp[-2] + 3);//stprintf("%s\n", cpp[-1][-1] + 1);//ewreturn 0;
}