当前位置: 首页 > news >正文

指针 (六):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.h
2. 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;
}
http://www.xdnf.cn/news/1377235.html

相关文章:

  • 深度学习:常用的损失函数的使用
  • Python随机选择完全指南:从基础到高级工程实践
  • 数据库:缓冲池和磁盘I/O
  • FPGA入门学习路径
  • 【Python 提高】GUI 界面 Tkinter 库布局管理器 Pack 方法开发指南
  • 树的常见算法及Java实现
  • 【yocto】Yocto Project 核心:深入了解.inc文件
  • Java循环结构全解析
  • android 嵌套webview 全屏展示 页面延伸到状态栏且不被底部导航栏遮挡
  • 高并发内存池(11)-PageCache获取Span(下)
  • 【C++标准库】<ios>详解基于流的 I/O
  • 腾讯云 CVM 上的 SpringBoot 应用避免非法访问
  • 寄存器的原理
  • YOLOv8-SMOT:一种高效鲁棒的实时小目标跟踪框架:基于切片辅助训练与自适应关联
  • 人工智能-python-深度学习-反向传播优化算法
  • ESP32使用场景及大规模物联网IoT
  • 流水线用到的Dockerfile和构建脚本build.sh
  • 如何安装 mysql-installer-community-8.0.21.0.tar.gz(Linux 详细教程附安装包下载)​
  • 神经网络学习笔记11——高效卷积神经网络架构SqueezeNet
  • 聊一聊 单体分布式 和 微服务分布式
  • 深度学习——优化函数
  • 自学嵌入式第二十九天:Linux系统编程-线程
  • flume监控文件写入 Kafka 实战:解耦应用与消息队列的最佳实践
  • 在语言模型监督式微调(SFT)中的 负对数似然(Negative Log-Likelihood, NLL)等价于最大化似然
  • 软考-系统架构设计师 管理信息系统(MIS)详细讲解
  • 为什么编码智能体可以重塑开发范式?
  • 【Mascaret】QGIS中Mascaret插件的使用
  • ESP8266:Arduino学习
  • 高并发内存池(12)-ThreadCache回收内存
  • 【HTML】隐藏滚动条但保留功能