C语言.指针(5)

指针(5)

  • 1.sizeof和strlen的对比
    • 1.1sizeof
    • 1.2strlen
    • 1.3sizeof和strlen的对比
  • 2.数组和指针笔试题解析
    • 2.1一维数组
    • 2.2字符数组
    • 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.1sizeof

sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。

sizeof 只关注占用内存空间的大小,不在乎内存存放的是什么数据。

比如:

#include<stdio.h>int main()
{int a = 0;printf("%zd\n", sizeof(a));//4printf("%zd\n", sizeof a);//4printf("%zd\n", sizeof(int));//4return 0;
}

1.2strlen

strlen 是C语言库函数,功能是求字符串长度。函数原型如下:

size_t strlen(const char* str);

统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。

strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。

#include <stdio.h>
#include <string.h>int main()
{char arr1[3] = { 'a', 'b', 'c' };char arr2[] = { "abc" };printf("%zd\n", strlen(arr1));//35:随机值printf("%zd\n", strlen(arr2));//3printf("%zd\n", sizeof(arr1));//3printf("%zd\n", sizeof(arr2));//4return 0;
}

1.3sizeof和strlen的对比

在这里插入图片描述

2.数组和指针笔试题解析

2.1一维数组

#include<stdio.h>
#include<string.h>int main()
{int a[] = { 1,2,3,4,5,6,7,8,9,10 };printf("%zd\n", sizeof(a));//a表示的是整个数组的地址,所以是sizeof(int)*10 == 40个字节printf("%zd\n", sizeof(a + 0));//a表示的是数组首元素的地址,计算的是首元素的地址,是地址就是4/8个字节printf("%zd\n", sizeof(*a));//a表示的是数组首元素的地址,*a表示的是 首元素的大小,是int类型,为4个字节printf("%zd\n", sizeof(a + 1));//a表示的是数组首元素的地址,a + 1,表示的是a[1]的地址,是地址就是4/8个字节printf("%zd\n", sizeof(a[0]));//a表示的是数组首元素的地址,a[0]表示的是数组首元素,是int类型,为4个字节printf("%zd\n", sizeof(a[1]));//a表示的是数组首元素的地址,a[1]表示的是第二个元素,是int类型,为4个字节printf("%zd\n", sizeof(&a));//&a,表示的是取出的是整个数组的地址,是地址就是4/8个字节printf("%zd\n", sizeof(&a + 1));//&a,表示的是取出的是整个数组的地址,&a + 1就跳出整个整型数组,是地址就是4/8个字节printf("%zd\n", sizeof(&a[0]));//&a[0]表示的是首元素的地址,是地址就是4/8个字节printf("%zd\n", sizeof(&a[0] + 1));//&a[0]表示的是首元素的地址,&a[0] + 1表示的是下标为1的元素的地址,是地址就是4/8个字节return 0;
}

2.2字符数组

代码1:

#include <stdio.h>int main()
{char arr[] = { 'a','b','c','d','e','f' };//             a b c d e f printf("%zd\n", sizeof(arr));//arr表示的是整个数组的地址,所以是sizeof(char)*6 == 6个字节printf("%zd\n", sizeof(arr + 0));//arr + 0表示的是数组首元素的地址,是地址就是4/8个字节printf("%zd\n", sizeof(*arr));//arr表示的是整个数组的地址,*arr得到的是首元素,arr的类型是char,是1个字节printf("%zd\n", sizeof(arr[1]));//arr[1],表示的是下标为1的数组元素,类型是char,是1个字节printf("%zd\n", sizeof(&arr));//&arr表示取出的是整个数组的地址,是地址就是4/8个字节printf("%zd\n", sizeof(&arr + 1));//&arr,表示的是取出的是整个数组的地址,&a + 1就跳出整个字符数组,是地址就是4/8个字节printf("%zd\n", sizeof(&arr[0] + 1));//&arr[0]表示的是首元素的地址,&arr[0] + 1表示的是下标为1的数组元素的地址,是地址就是4/8个字节return 0;
}

代码2:

#include <stdio.h>
#include<string.h>
//size_t strlen ( const char * str );
//strlen()需要的是首元素的地址
int main()
{char arr[] = { 'a','b','c','d','e','f' };//              a b c d e fprintf("%zd\n", strlen(arr));//arr表示的是首元素的地址,数组中没有\0,就会导致越界访问,结果就会是随机值printf("%zd\n", strlen(arr + 0));//arr表示的是首元素的地址,数组中没有\0,就会导致越界访问,结果就会是随机值printf("%zd\n", strlen(*arr));//arr是首元素的地址,*arr是首元素,就是'a','a'的ASCII码值是97,相当于把97当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误//errprintf("%zd\n", strlen(arr[1]));//arr[1]表示的是下标为1的数组元素,就是'b','b'的ASCII码值是98,相当于把98当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误//errprintf("%zd\n", strlen(&arr));//&arr表示取出的是整个数组的地址,数组中没有\0,就会导致越界访问,起始位置指向数组的第一个元素的位置,结果就会是随机值 xprintf("%zd\n", strlen(&arr + 1));//&arr表示取出的是整个数组的地址,&arr + 1跳过整个数组的地址,数组中没有\0,就会导致越界访问,起始位置指向数组的最后一个元素的下一个位置,结果就会是随机值 x - 6printf("%zd\n", strlen(&arr[0] + 1));//从第2个元素开始向后统计的,得到的也是随机值 x - 1return 0;
}

代码3:

#include <stdio.h>
#include <string.h>int main()
{char arr[] = { "abcdef" };//              a b c d e f \0printf("%zd\n", sizeof(arr));//arr表示的是整个数组的地址,计算的是整个数组的大小,sizeof(char)*7 == 7个字节printf("%zd\n", sizeof(arr + 0));//arr + 0表示的是数组首元素的地址,是地址就是4/8个字节printf("%zd\n", sizeof(*arr));//*arr得到的是数组的首元素,类型是char,1个字节printf("%zd\n", sizeof(arr[1]));//arr[1]是数组下标为1的元素,类型是char,1个字节printf("%zd\n", sizeof(&arr));//&arr取出的是整个数组的地址,是地址就是4/8字节printf("%zd\n", sizeof(&arr + 1));//&arr取出的是整个数组的地址,&arr + 1跳过整个数组,还是地址,是地址就是4/8个字节printf("%zd\n", sizeof(&arr[0] + 1));//&arr[0]表示的是数组首元素的地址,&arr[0] + 1就是下标为1的数组元素的地址,是地址就是4/8个字节return 0;
}

代码4:

#include <stdio.h>
#include<string.h>int main()
{char arr[] = "abcdef";//            a b c d e f \0printf("%zd\n", strlen(arr));//arr首元素的地址,向后在\0之前有6个字符printf("%zd\n", strlen(arr + 0));//arr首元素的地址,arr+0还是首元素的地址,向后在\0之前有6个字符printf("%zd\n", strlen(*arr));//arr是首元素的地址,*arr是首元素,就是'a','a'的ASCII码值是97,相当于把97当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误printf("%zd\n", strlen(arr[1]));//arr[1]是下标为1数组的元素,就是'b','b'的ASCII码值是98,相当于把98当作地址传给strlen(),strlen得到的就是野指针, 代码是有问题的,结果错误printf("%zd\n", strlen(&arr));//&arr表示取出的是整个数组的地址,起始位置指向数组的第一个元素的位置,向后在\0之前有6个字符printf("%zd\n", strlen(&arr + 1));//&arr表示取出的是整个数组的地址,&arr + 1跳过整个数组的地址,起始位置指向数组的最后一个元素的下一个位置,数组中没有\0,就会导致越界访问,结果就会是随机值printf("%zd\n", strlen(&arr[0] + 1));//&arr[0]表示的是数组首元素的地址,&arr[0] + 1就是下标为1的数组元素的地址,向后在\0之前有5个字符return 0;
}

代码5:

#include <stdio.h>int main()
{const char* p = "abcdef";//               a b c d e f \0printf("%zd\n", sizeof(p));//p是指针变量,计算的是指针变量的大小,4/8个字节printf("%zd\n", sizeof(p + 1));//p + 1是b的地址,是地址大小就是4/8个字节printf("%zd\n", sizeof(*p));//p的类型是const char*,*p就是char类型,大小是1个字节printf("%zd\n", sizeof(p[0]));//1.p[0] -> *(p + 0) -> *p -> 得到的就是'a',大小是1个字节//2.把常量字符串想象成数组,p可以理解为数组名,p[0], 就是首元素printf("%zd\n", sizeof(&p));//取出的是p的地址,地址的大小是4/8个字节printf("%zd\n", sizeof(&p + 1));//&p + 1是跳过p指针变量后的地址,是地址就是4/8个字节printf("%zd\n", sizeof(&p[0] + 1));//&p[0]表示的是取出字符串首字符的地址,&p[0] + 1是第二个字符的地址,大小是4/8个字节return 0;
}

代码6:

#include <stdio.h>
#include <string.h>int main()
{const char* p = "abcdef";//               a b c d e f \0printf("%zd\n", strlen(p));//p是指针变量,向后在\0之前有6个字符printf("%zd\n", strlen(p + 1));//p是指针变量,p + 1向后在\0之前有5个字符//printf("%zd\n", strlen(*p));//p的类型是const char*,*p就是char类型,*p就是'a'-97,err//printf("%zd\n", strlen(p[0]));//p[0] -> *(p + 0) -> *p -> 得到的就是'a'-97.errprintf("%zd\n", strlen(&p));//&p是指针变量p的地址,和字符串"abcdef"关系不大,从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以是随机值printf("%zd\n", strlen(&p + 1));//和上面的情况一样了,随机值printf("%zd\n", strlen(&p[0] + 1));//p[0] -> *(p + 0) -> *p,&p[0] == &*p == p:首元素的地址//&p[0]-取出字符串首字符的地址,+1是第二个字符的地址, 5return 0;
}

2.3二维数组

#include<stdio.h>int main()
{int a[3][4] = { 0 };printf("%zd\n", sizeof(a));//a是二维数组的数组名,单独放在sizeof()中,计算的是整个数组的大小,3*4*sizeof(int) == 48个字节printf("%zd\n", sizeof(a[0][0]));//a[0][0] 是第一行第一个元素,大小是4个字节 printf("%zd\n", sizeof(a[0]));//a[0]表示的是第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节printf("%zd\n", sizeof(a[0] + 1));//a[0] + 1表示的是第二行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节printf("%zd\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)表示的是第一行第二个元素,大小就是4//*(*(p + 0) + 1) == p[0][1]printf("%zd\n", sizeof(a + 1));//a表示数组首元素的地址,是二维数组首元素的地址,也就是第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址,a+1是数组指针,是地址大小就是4/8个字节printf("%zd\n", sizeof(*(a + 1)));//1.a表示数组首元素的地址,是二维数组首元素的地址,也就是第一行的地址,a+1,跳过一行,指向了第二行,*(a+1)表示的是第二行,a+1是数组指针,计算的是第二行的大小 - 16字节//2.*(a + 1) == a[1] -> 表示的是第二行的数组名,单独放在sizeof中,4*sizeof(int) == 16字节printf("%zd\n", sizeof(&a[0] + 1));//&a[0]取出的是第一行的数组名,&a[0] + 1指向的是第二行的地址,是地址大小就是4/8个字节printf("%zd\n", sizeof(*(&a[0] + 1)));//&a[0] + 1指向的是第二行的地址,*(&a[0] + 1)是对第二行的地址解引用,访问的就是第二行,大小是16字节printf("%zd\n", sizeof(*a));//1.a表示的是二维数组首元素的地址,计算的就是第一行的大小,16字节//2.*a == *(a + 0) == a[0] ->第一行的数组名printf("%zd\n", sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型的推断就能算出长度a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16个字节return 0;
}

数组名的意义:

  1. sizeof(数组名),这⾥的数组名表示整个数组,计算的是整个数组的大小。
  2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表表示首元素的地址。

3.指针运算笔试题解析

3.1 题目1

#include <stdio.h>int main()
{int a[] = { 1,2,3,4,5 };int* ptr = (int*)(&a + 1);printf("%d %d\n", *(a + 1), *(ptr - 1));//                  2         5return 0;
}
//输出的结果是什么?

3.2 题目2

//在X86的环境下
//假设结构体的大小是20个字节
//输出的结果是什么?
#include <stdio.h>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.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]);//1return 0;
}

3.4 题目4

//假设环境是x86环境,程序输出的结果是啥?
#include<stdio.h>int main()
{int a[5][5];int(*p)[4];//p是一个数组指针,p指向的数组是4个整型元素p = a;printf("%p, %d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//                 FFFFFFFC,            -4return 0;
}

3.5 题目5

#include<stdio.h>int main()
{int a[2][5] = { 1,2,3,4,5,6,7,8,9,10 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)(*(a + 1));printf("%d, %d\n", *(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);//atreturn 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/810308.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聊一聊分库分表(是什么?怎么分?有什么坑?)

目录 为什么会分表分库&#xff1f; 数据分表 怎么分表&#xff1f; 垂直分表 好处&#xff1a; 缺点&#xff1a; 水平分表 优点&#xff1a; 缺点&#xff1a; 数据分库 怎么分库&#xff1f; 水平分库 适用场景&#xff1a; 优点&#xff1a; 注意事项&#x…

中科方德服务器操作系统安装zabbix5.0

原文链接&#xff1a;中科方德服务器操作系统安装zabbix5.0 Hello&#xff0c;大家好啊&#xff01;接着我们上一次的讨论&#xff0c;今天我要为大家介绍如何在已经安装好的中科方德服务器操作系统基础上&#xff0c;安装和配置Zabbix 5.0。Zabbix是一个开源的监控软件工具&am…

LeetCode-416. 分割等和子集【数组 动态规划】

LeetCode-416. 分割等和子集【数组 动态规划】 题目描述&#xff1a;解题思路一&#xff1a;01背包问题&#xff0c;动规五部曲解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分…

python爬虫 - 下载图片

文章目录 1、下载图片示例1&#xff1a;使用 .urlretrieve() 函数2、下载图片示例2 - 使用 open/write 函数3、下载图片示例33.1 使用 open/write 下载3.2 使用 urlretrieve下载 爬虫的本质&#xff1a;模拟对应的App&#xff0c;浏览器访问对应的地址获取到数据 1、下载图片示…

考虑预同步的虚拟同步机T型三电平逆变器并离网MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 三相 T 型三电平逆变器电路如图所示&#xff0c;逆变器主回路由三个单相 T 型逆变器组成。 直流侧输入电压为 UPV&#xff0c;直流侧中点电位 O 设为零电位&#xff0c;交流侧输出侧是三相三线制连…

4.双向循环链表的模拟实现

1.双向链表的实现 1.1双向链表节点的结构声明 typedef int LTDataType;typedef struct ListNode {struct ListNode* prev; // 指向该节点的前一个节点struct ListNode* next; // 指向该节点的后一个节点LTDataType data; // 该节点中存储的数据 }LTNode; // 将这…

Linux内核errno-base.h源码分析

上次写过一个博客&#xff0c;主要关于内核错误相关的源码分析&#xff08;链接&#xff09;&#xff0c;最近突然发现上次的分析不完善&#xff0c;因此本次完善相关分析。 Linux内核中经常见到一些返回值&#xff0c;如-12&#xff0c;比如下面是我遇到过的一个截图&#xff…

【Java面试题】MySQL上篇(索引)

文章目录 索引1.索引的分类&#xff1f;2.B树和B树的区别&#xff1f;2.1B树2.2B树 3.为什么使用索引会加快查询&#xff1f;4.创建索引的注意点&#xff1f;5.索引在哪些情况下会失效&#xff1f;6.聚簇索引和非聚簇索引的区别&#xff1f;7.回表查询是什么&#xff1f;8.什么…

阿里云租用服务器GPU配置报价单_1年_一个月_1小时价格表

阿里云GPU服务器租用价格表包括包年包月价格、一个小时收费以及学生GPU服务器租用费用&#xff0c;阿里云GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡&#xff0c;GPU云服务器gn6i可享受3折优惠&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云GPU…

电脑磁盘空间不足?学会这几招,轻松释放磁盘空间

随着科技的飞速发展&#xff0c;电脑已成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐&#xff0c;我们都需要依赖电脑来完成。然而&#xff0c;随着电脑使用时间的增长&#xff0c;磁盘空间不足的问题也逐渐浮现。当磁盘空间不足时&#xff0c;不仅会影响电脑…

2023年金融贷款骗局套路之一

源地址&#xff1a;2023年金融贷款骗局套路之一_预防网贷套路_计算机技术网 随着无卡消费的日夜流行&#xff0c;三年疫情出现&#xff0c;钱难寻&#xff0c;难找的尴尬境地&#xff0c;贷款骗局也出现不少。今天我们讲讲最近很流行的贷款骗局之一中的一种贷款骗局。 在平常…

第40篇:有限状态机<三>

Q&#xff1a;本期我们介绍有限状态机的应用之一&#xff1a;摩尔状态机“1101”序列检测器。 A&#xff1a;当检测到序列1101时&#xff0c;状态机输出为1。定义s_0为初始状态&#xff08;即没有检测到1输入的状态&#xff09;&#xff0c;摩尔状态机的输出仅取决于现态&…

基于SpringBoot+Vue的个性化推荐电商平台(源码+文档+部署+讲解)

一.系统概述 随着网络科技的不断发展以及人们经济水平的逐步提高&#xff0c;网络技术如今已成为人们生活中不可缺少的一部分&#xff0c;而信息管理系统是通过计算机技术&#xff0c;针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;有…

数学建模-Matlab中randperm函数及其双重进阶版

1.randperm函数的用法 &#xff08;1&#xff09;这种用法就是参数只有一个数字&#xff0c;代表的含义就是随机排列之后打印输出&#xff1b; 我们举例的数字是4&#xff0c;就会把1到4这4个数字随机打乱之后随机输出&#xff0c;每次运行结果都不一样 所有可能的情况是n的…

UI自动化测试案例

备注:本文为博主原创文章,未经博主允许禁止转载。如有问题,欢迎指正。 个人笔记(整理不易,有帮助,收藏+点赞+评论,爱你们!!!你的支持是我写作的动力) 笔记目录:笔记本~笔记目录_airtest和selenium那个好用-CSDN博客 个人随笔:工作总结随笔_8、以前工作中都接触过哪…

鸿蒙南向开发:【智能烟感】

样例简介 智能烟感系统通过实时监测环境中烟雾浓度&#xff0c;当烟雾浓度超标时&#xff0c;及时向用户发出警报。在连接网络后&#xff0c;配合数字管家应用&#xff0c;用户可以远程配置智能烟感系统的报警阈值&#xff0c;远程接收智能烟感系统报警信息。实现对危险及时报…

Java区域基层卫生云联his系统源码 医院信息管理系统源码

基于云计算的医疗卫生信息系统(cloud-based healthcare informationsystem&#xff0c;简称“云 HIS”)是基于云计算技术&#xff0c;将医院信息系统、电子病历系统、实验室信息系统、公共卫生等系统横向集成的系统&#xff0c;为医疗机构信息化建设提供标准化、信息化、协同化…

003Node.js创建第一个web服务

如果用PHP来编写后端代码&#xff0c;需要用Apache或者Nginx的服务器,来处理客户的请求响应。对于Node.js时&#xff0c;不仅实现了应用&#xff0c;同时还实现了整个HTTP服务器. 安装 Node Snippets插件&#xff08;编程自带提示&#xff09; console.log(你好nodejs); //表…

代理模式:控制对象访问的智能方式

在面向对象的软件开发中&#xff0c;代理模式是一种结构型设计模式&#xff0c;它为其他对象提供一个代理或占位符以控制对这个对象的访问。代理模式在实现权限控制、延迟初始化和远程对象访问等方面非常有用。本文将详细介绍代理模式的定义、实现、应用场景以及优缺点&#xf…