C语言 --- 指针(5)

目录

一.sizeof和strlen对比

1.sizeof

2.strlen

3.strlen 和sizeof的对比

二.数组和指针笔试题目详解

 回顾:数组名的理解

1.一维数组

2.字符数组 

代码1:

 代码2:

 代码3:

代码4:

代码5:

代码6:

3.二维数组 

总结 


一.sizeof和strlen对比

1.sizeof

sizeof既是一种关键字也是一个操作符。sizeof的作用是计算变量和类型的所占内存空间的大小,单位是字节,返回size_t类型的值。sizeof只关注所占用内存空间的大小,不在乎内存中存放的什么数据。

比如:

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

sizeof在使用时,可以不用括号,这证明了它不是一个函数,但是在计算类型比如int就不行,必须加括号。

打印结果都是4,size_t类型的值应该用%zd打印,但是这里也可以使用%d,只不过编译器会发出警告,但是影响不大。

sizeof不关注括号中的数据,只关注存放内存的大小。比如:

#include<stdio.h>
int main()
{int a = 10;int size = sizeof(a++);printf("%d\n",size);printf("%d\n",a);return 0;
}

输出结果是4  10

很明显sizeof括号中的表达式是没有计算的。 

2.strlen

strlen是C语言库函数,在使用时需要包含头文件<string.h>

函数原型:

size_t strlen(const char *str);

这个函数会返回字符串中字符数,但是不包括\0,也就是返回的是\0之前的字符数。如果没有\0就会出现越界查找的情况。

比如:

#include<stdio.h>
int main()
{char arr1[] = {'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;
}

打印结果是 随机值 3 3 4.

第一个是随机值的原因就是没有\0,strlen会一直查找直到遇到\0才终止。

第二个因为是常量字符串,包含\0,所以是3。

第三个计算的是数组arr1中所占内存的大小,只有三个字符,也就是3个字节。

第四个arr2中有\0,所以是4个字节。

3.strlen 和sizeof的对比

sizeofstrlen
  1. sizeof是操作符。
  2. sizeof计算的是操作数所占内存空间的大小,单位是字节。
  3. 不关注内存中存放的什么数据。
  1. strlen是库函数,使用的头文件是<string.h>。
  2. strlen是求字符串长度的,统计的是\0之前的字符个数。
  3. strlen关注内存中是否有\0,如果没有\0,就会继续往前找,可能会出现越界的情况。

二.数组和指针笔试题目详解

 回顾:数组名的理解

 数组名是数组首元素的地址。

但是有两个的特殊情况

  1. sizeof(数组名) ,sizeof中单独放数组名,这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节。
  2. &数组名,这里的数组名代表的是整个数组,&取出的是整个数组的地址。(整个数组的地址虽然和数组首元素的地址是相同的,但是指针变量的类型是不同的。)

1.一维数组

#include<stdio.h>
int main()
{int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));//1printf("%d\n", sizeof(a + 0));//2printf("%d\n", sizeof(*a));//3printf("%d\n", sizeof(a + 1));//4printf("%d\n", sizeof(a[1]));//5printf("%d\n", sizeof(&a));//6printf("%d\n", sizeof(*&a));//7printf("%d\n", sizeof(&a + 1));//8printf("%d\n", sizeof(&a[0]));//9printf("%d\n", sizeof(&a[0] + 1));//10return 0;
}
序号解析答案
1 a是数组名,sizeof中单独放数组名,计算的是整个数组的大小,单位字节。16
2sizeof中没有单独放数组名a,所以这里的数组名就是数组首元素的地址,地址就是指针变量。在不同环境下大小不同。4 || 8
3a是数组首元素的地址,解引用后得到数组首元素。所以计算的是整形变量的大小。4
4a表示数组首元素的地址,地址就是指针,类型是int*,指针加1跳过4个字节,也就是一个整形元素,也就是第二个元素的地址。4 || 8
5a[1]表示数组第二个元素4
6&a是整个数组的地址,地址就是指针变量.4 || 8
7&a是整个数组的地址,解引用后就是整个数组。所以sizeof计算的是整个数组的大小(&和*可以相互抵消16
8&a是整个数组的地址,+1跳过了整个数组,虽然这个地址并没有指向这个数组了,但是我们并没有越界访问,所以不影响sizeof计算这个指针变量的大小。4 || 8
9&a[0]得到的是数组首元素的地址.4 || 8
10&a[0]+1,跳过一个元素,得到的是数组第二个元素的地址。4 || 8

2.字符数组 

代码1:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7
序号解析答案
1arr单独放在sizeof中,计算的是整个数组的大小。单位字节6
2arr没有单独放在数组中,arr表示的是数组首元素的地址4 || 8
3arr表示的是数组首元素的地址,解引用后得到的是数组首元素。1
4arr[1]表示数组首元素。1
5&arr表示整个数组的地址,地址就是指针变量4 || 8
6

&a是整个数组的地址,+1跳过了整个数组,虽然这个地址并没有指向这个数组了,但是我们并没有越界访问,所以不影响sizeof计算这个指针变量的大小。

4 || 8
7&arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址4 || 8

 代码2:

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr+0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr+1));//6
printf("%d\n", strlen(&arr[0]+1));//7
序号解析答案
1arr是数组首元素的地址,strlen计算的是'\0'之前的字符个数,但是这个数组中并没有'\0',所以会出现越界的情况,故无法出现准确的值的情况。随机值
2这里的arr也是数组首元素的地址,+0并没有跳过任何字节,与序号1同理也是不确定情况。(两个值应该是一样的)随机值
3strlen的参数是const char *类型的。*arr得到的是数组首元素,将这个作为参数传给strlen是不行的,这里程序会崩溃。error
4arr[1]表示数组第二个元素,将其作为参数传给strlen是不行的。error
5&arr表示整个数组的地址,虽然是一个数组指针变量,但是传参会进行强制类型转换为char*类型,值和数组首元素的地址相同,所以和序号1和2相同,值一样的。随机值
6

&a是整个数组的地址,+1跳过了整个数组,也就是跳过了6个字节。但是因为没有'\0',也会出现随机的情况

随机值(比序号125小6)
7&arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,只跳过了1个字节。随机值(比序号125小1)

输出结果:(以下是随机值,不是特定情况。)

 

序号3和4已被注释掉了。

 代码3:

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//1
printf("%d\n", sizeof(arr+0));//2
printf("%d\n", sizeof(*arr));//3
printf("%d\n", sizeof(arr[1]));//4
printf("%d\n", sizeof(&arr));//5
printf("%d\n", sizeof(&arr+1));//6
printf("%d\n", sizeof(&arr[0]+1));//7
序号解析答案
1sizeof(数组名),计算的是整个数组的大小,字符串末尾是有一个'\0'的,只不过没有显示出来,我们可以通过调试观察,所以这个字符串中有7个字符。7
2这里的arr也是数组首元素的地址,+0并没有跳过任何字节,是一个指针变量。4 || 8
3*arr的到的数组首元素。1
4arr[1]表示数组第二个元素.1
5&arr表示整个数组的地址,是一个指针变量。4 || 8
6

&a是整个数组的地址,+1跳过了整个数组,但是还是一个指针变量

4 || 8
7&arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,是一个指针变量4 || 8

序号1:

我们可以看到数组中分别放着不同的字符,字符前面是它们的ASCII码值,arr[6],也就是数组的第7个元素,存放着'\0'字符。

代码4:

char arr[] = "abcdef";
printf("%d\n", strlen(arr));//1
printf("%d\n", strlen(arr+0));//2
printf("%d\n", strlen(*arr));//3
printf("%d\n", strlen(arr[1]));//4
printf("%d\n", strlen(&arr));//5
printf("%d\n", strlen(&arr+1));//6
printf("%d\n", strlen(&arr[0]+1));//7
序号解析答案
1sizeof计算的是'\0'之前的地址,有6个字符6
2sizeof计算的是'\0'之前的地址,有6个字符6
3*arr的到的数组首元素。不应该作为参数传给strlenerror
4arr[1]表示数组第二个元素.不应该作为参数传给strlenerror
5&arr表示整个数组的地址,sizeof计算的是'\0'之前的地址,有6个字符.6
6

&a是整个数组的地址,+1跳过了整个数组,故不知道什么时候会遇到'\0',所以是个随机值

随机值
7&arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,从第二个开始到'\0',有5个字节。5

输出结果:

序号6就是经过了16个字符才遇到'\0',error情况已经注释掉了。

代码5:

char *p = "abcdef";
printf("%d\n", sizeof(p));//1
printf("%d\n", sizeof(p+1));//2
printf("%d\n", sizeof(*p));//3
printf("%d\n", sizeof(p[0]));//4
printf("%d\n", sizeof(&p));//5
printf("%d\n", sizeof(&p+1));//6
printf("%d\n", sizeof(&p[0]+1);//7
序号解析答案
1sizeof计算的是'\0'之前的地址,有6个字符6
2sizeof计算的是'\0'之前的地址,有6个字符6
3*arr的到的数组首元素。不应该作为参数传给strlenerror
4arr[1]表示数组第二个元素.不应该作为参数传给strlenerror
5&arr表示整个数组的地址,sizeof计算的是'\0'之前的地址,有6个字符.6
6

&a是整个数组的地址,+1跳过了整个数组,故不知道什么时候会遇到'\0',所以是个随机值

随机值
7&arr[0]表示数组首元素的地址,+1跳过一个元素,表示数组第二个元素的地址,从第二个开始到'\0',有5个字节。5

代码6:

char *p = "abcdef";
printf("%d\n", strlen(p));//1
printf("%d\n", strlen(p+1));//2
printf("%d\n", strlen(*p));//3
printf("%d\n", strlen(p[0]));//4
printf("%d\n", strlen(&p));//5
printf("%d\n", strlen(&p+1));//6
printf("%d\n", strlen(&p[0]+1));//7
序号解析答案
1sizeof计算的是'\0'之前的地址,有6个字符6
2sizeof计算的是'\0'之前的地址,+1后跳过一个字节,也就是一个元素,有5个字符5
3*p的到的数组首元素。不应该作为参数传给strlenerror
4p[0]表示数组第一个元素.不应该作为参数传给strlenerror
5&p表示字符指针的地址,sizeof计算的是'\0'之前的地址,会产生随机值随机值
6

&p是字符指针的地址,加1 跳过4 || 8个字节,故不知道什么时候会遇到'\0',所以是个随机值

随机值
7&p[0]表示首首字符的地址,+1跳过一个元素,表示第二个字符的地址,从第二个开始到'\0',有5个字节。5

输出结果:

3.二维数组 

int a[3][4] = {0};
printf("%d\n",sizeof(a));//1
printf("%d\n",sizeof(a[0][0]));//2
printf("%d\n",sizeof(a[0]));//3
printf("%d\n",sizeof(a[0]+1));//4
printf("%d\n",sizeof(*(a[0]+1)));//5
printf("%d\n",sizeof(a+1));//6
printf("%d\n",sizeof(*(a+1)));//7
printf("%d\n",sizeof(&a[0]+1));//8
printf("%d\n",sizeof(*(&a[0]+1)));//9
printf("%d\n",sizeof(*a));//10
printf("%d\n",sizeof(a[3]));//11
序号解析

答案

1数组名a单独放在sizeof中,计算的是整个数组的大小。48 = 3 * 4 * sizeof(int)
2a[0][0]表示数组第一行第一个元素。4
3
  1. a[0]表示二维数组首元素地址,也就是第一个一维数组的数组名,a[0]就是单独存放在sizeof的数组名,计算的就是第一个一维数组的大小.
  2. a[0]可以写成*(a + 0),a是二维数组的第一个一维数组的地址,解引用就是第一个一维数组了.
4 * sizeof(int) = 16
4a[0]表示第一个一维数组的数组名,并没有单独放在sizeof中,代表首元素的地址,+1,跳过一个元素,也就是&a[0][1].4 || 8
5解引用后得到的是a[0][1]4
6a表示数组首元素的地址,+1就是第二个元素的地址,也就是第二个一维数组的地址,4 || 8
7解引用后就是第二个一维数组。16
8a[0]是第一行的数组名,&a[0]就是第一行的地址,+1后是第二行的地址,地址就是指针4 || 8
9解引用后就是第二行,计算的第二行的大小16
10*a就是第一行,计算的就是第一行的大小16
11a[3]是第四行的数组名,虽然没有第四行,但是sizeof并没有进行访问,所以并不是越界访问,根据类型仍然可以计算第四行的大小,4个整形变量。16

总结 

数组名的意义:

  1.  sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。
  2.  & 数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表⽰⾸元素的地址。

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

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

相关文章

SSM整合项目(使用Vue3 + Element-Plus创建项目基础页面)

1.配置Vue启动端口 1.修改vue.config.js const {defineConfig} require(vue/cli-service) module.exports defineConfig({transpileDependencies: true }) module.exports {devServer: {port: 9999 //启动端口} }2.启动 2.安装Element Plus 命令行输入 npm install eleme…

【leetcode热题】排序链表

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&#xff1a; 输入…

骑行瓦恭村的记忆

昆富公路是一条蜿蜒的丝带&#xff0c;引领着校长骑行这群热爱骑行的骑友&#xff0c;穿越时光的隧道&#xff0c;直达心灵深处那个被岁月抚摸得斑斑点点的小村庄——瓦恭村。大普吉隧道如同时光的门扉&#xff0c;每一次穿越&#xff0c;都伴随着轰鸣的排气扇声音&#xff0c;…

新规正式发布 | 百度深度参编《生成式人工智能服务安全基本要求》

2024年2月29日&#xff0c;全国网络安全标准化技术委员会&#xff08; TC260 &#xff09;正式发布《生成式人工智能服务安全基本要求》&#xff08;以下简称《基本要求》&#xff09;。《基本要求》规定了生成式人工智能服务在安全方面的基本要求&#xff0c;包括语料安全、模…

HarmonyOS 关系型数据 整体测试 进行 初始化 增删查改 操作

好啊 前面的文章 HarmonyOS 数据持久化 关系型数据库之 初始化操作 HarmonyOS 数据持久化 关系型数据库之 增删改逻辑编写 HarmonyOS 数据持久化 关系型数据库之 查询逻辑编写 我们分别编写了 初始化数据库表 增删查改操作 的逻辑代码 那么 下面我们就来整体操作一下 然后 这…

Python中的并发编程:多线程与多进程的比较【第124篇—多线程与多进程的比较】

Python中的并发编程&#xff1a;多线程与多进程的比较 在Python编程领域中&#xff0c;处理并发任务是提高程序性能的关键之一。本文将探讨Python中两种常见的并发编程方式&#xff1a;多线程和多进程&#xff0c;并比较它们的优劣之处。通过代码实例和详细的解析&#xff0c;…

Helix QAC—源码级静态自动化测试工具

Helix QAC概述 Helix QAC是一款源码级静态自动化测试工具&#xff0c;主要用于C/C代码的完全自动化静态分析工作&#xff0c;提供一个高效、健壮和自动化的环境来引入和执行编码标准。Helix QAC根据尽早、更频繁测试的理念&#xff0c;在软件生命周期最早期软件开发阶段应用识别…

Linux学习——线程的控制

目录 ​编辑 一&#xff0c;线程的创建 二&#xff0c;线程的退出 1&#xff0c;在子线程内return 2,使用pthread_exit(void*) 三&#xff0c;线程等待 四&#xff0c;线程获取自己的id值 五&#xff0c;线程取消 六&#xff0c;线程分离 一&#xff0c;线程的创建 在对…

JavaEE企业开发新技术2

目录 2.7 Field类的基本概念 文字性概念描述&#xff1a; Field类 2.8 Field的基本操作-1 2.9 Field的基本操作-2 分析&#xff1a; 2.10 Field 的综合练习 总结&#xff1a; 和equals的区别&#xff1a; 使用 比较 使用equals比较 2.7 Field类的基本概念 文字性…

IAR全面支持小华全系芯片,强化工控及汽车MCU生态圈

IAR Embedded Workbench for Arm已全面支持小华半导体系列芯片&#xff0c;加速高端工控MCU和车用MCU应用的安全开发 嵌入式开发软件和服务的全球领导者IAR与小华半导体有限公司&#xff08;以下简称“小华半导体”&#xff09;联合宣布&#xff0c;IAR Embedded Workbench fo…

微信小程序开发系列(二十四)·wxml语法·列表渲染·wx:for-item 和 wx:for-index

目录 1. 如果需要对默认的变量名和下标进行修改&#xff0c;可以使用wx:for-item 和 wx:for-index 2. 将 wx:for 用在 标签上&#xff0c;以渲染一个包含多个节点的结构块 方法一 方法二 3. 总结 3.1 wx:for-item 和 wx:for-index总结 3.2 总结 1. 如果需要对默…

简述epoll实现

所有学习笔记&#xff1a;https://github.com/Dusongg/StudyNotes 文章目录 epoll数据结构的选择&#xff1f;以tcp为例&#xff0c;网络io的可读可写如何判断&#xff1f;epoll如何做到线程安全&#xff1f;LT和ET如何实现&#xff1f;tcp状态和io的读写有哪些关系&#xff1…

ChatGPT等AI使用的过程苦笑不得瞬间

引言&#xff1a; 在人工智能的浪潮中&#xff0c;我们见证了技术的飞速发展和智能应用的广泛渗透。特别是随着语言模型的进步&#xff0c;AI如ChatGPT、文心一言、通义千问、讯飞星火等已经成为人们日常生活和工作中不可或缺的助手。然而&#xff0c;与任何新兴技术一样&#…

零售EDI:劳氏 Lowe‘s EDI项目案例

通过 EDI&#xff0c;企业与Lowes之间可以直接交换各种商业文档&#xff0c;如订单、发票、收据等&#xff0c;从而实现信息的实时交换&#xff0c;提高了供应链的效率和准确性。在现代供应链管理中&#xff0c;EDI 已经成为了不可或缺的重要工具。 作为一家拥有多条业务线的企…

力扣每日一题 找出数组的第 K 大和 小根堆 逆向思维(TODO:二分+暴搜)

Problem: 2386. 找出数组的第 K 大和 文章目录 思路复杂度&#x1f496; 小根堆&#x1f496; TODO&#xff1a;二分 暴搜 思路 &#x1f468;‍&#x1f3eb; 灵神题解 复杂度 时间复杂度: 添加时间复杂度, 示例&#xff1a; O ( n ) O(n) O(n) 空间复杂度: 添加空间复杂…

组态软件基础知识

一、组态软件基础知识 1、概述 &#xff08;1&#xff09;、组态软件概念与产生背景 “组态”的概念是伴随着集散型控制系统&#xff08;Distributed Control System简称DCS&#xff09;的出现才开始被广大的生产过程自动化技术人员所熟知的。在工业控制技术的不断发…

新手如何快速上手学习单片机?

读者朋友能容我&#xff0c;不使博文负真心 新开专栏&#xff0c;期待与诸君共享精彩 个人主页&#xff1a;17_Kevin-CSDN博客 专栏&#xff1a;《单片机》 学习单片机是一个有趣且有挑战性的过程。单片机是一种微控制器&#xff0c;广泛应用于各种电子设备和嵌入式系统中。在这…

大模型快速实现python3+html内容在线渲染

需求&#xff1a; 有一份数据需要通过前端在线展示给用户&#xff0c;不需要复杂的样式交互&#xff0c;后端服务是基于Python3实现的API接口&#xff0c;对前端技术不是很了解&#xff0c;需要快速实现该需求。类似样式即可&#xff1a; 思路&#xff1a; 如果页面不复杂&am…

开放式高实时高性能PLC控制器解决方案-基于米尔电子STM32MP135

前言 随着工业数字化进程加速与IT/OT深入融合&#xff0c;不断增加的OT核心数据已经逐步成为工业自动化行业的核心资产&#xff0c;而OT层数据具备高实时、高精度、冗余度高、数据量大等等特点&#xff0c;如何获取更加精准的OT数据对数字化进程起到至关重要的作用&#xff0c;…

编译支持国密的抓包工具 WireShark

目录 前言WireShark支持国密的 WireShark小结前言 在上一篇文章支持国密的 Web 服务器中,我们搭建了支持国密的 Web 服务器,但是,我们使用 360 安全浏览器去访问,却出现了错误: 是我们的 Web 服务器没有配置好?在这里插入图片描述还是 360 安全浏览器不支持国密?还是两…