【C语言】指针查漏补缺

news2024/12/23 17:49:23

【C语言】指针查漏补缺

  • 预备知识
  • 一维整数数组
  • 字符数组
  • 字符常量数组
  • 字符串常量
  • 二维数组

预备知识

  1. sizeof 是计算对象或者类型创建的对象所占内存空间的大小,单位是字节

  2. sizeof 是操作符,不是函数

  3. strlen 求字符串长度的,计算的是字符串中\0之前出现的字符的个数
    统计到\0为止,如果没有看到\0,会继续往后找

  4. strlen 是库函数size_t strlen ( const char * str );

关于数组名
数组名是数组首元素的地址
但是有2个例外:

  • sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
  • &数组名 - 数组名也表示整个数组,取出的是整个数组的地址

除了这个2个例外,所有的数组名都表示首元素的地址

一维整数数组

int main()
{
	int a[] = { 1,2,3,4 };
	int* p = a;
	//int (*pa)[4] = &a;
	printf("%p\n", p); 008FFCF4
	printf("%p\n", p+1); 008FFCF8

	printf("%p\n", pa); 008FFCF4
	printf("%p\n", pa+1); 008FFD04

	//a  - int*
	//&a - int (*)[4]

	printf("%d\n", sizeof(a));//16,a作为数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
	printf("%d\n", sizeof(a + 0));//a并非单独放在sizeof内部,也没有&,所以数组名a就是数组首元素的地址
	//a+0还是数组首元素的地址,是地址大小就是 4/8 个字节
	printf("%d\n", sizeof(*a));//a是首元素的地址,*a就是首元素,sizeof(*a)就算的就是首元素的大小 - 4
	//a  - int*
	//*a - int
	printf("%d\n", sizeof(a + 1));//a是首元素的地址,a+1是第二个元素的地址,sizeof(a+1)计算的是指针的大小 - 4/8
	//a - int*
	//a+1, 跳过一个int
	printf("%d\n", sizeof(a[1]));//a[1]就是数组的第二个元素,sizeof(a[1])的大小 - 4个字节
	printf("%d\n", sizeof(&a));//&a取出的数组的地址,数组的地址,也是地址呀,sizeof(&a)就是 4/8 个字节

	printf("%d\n", sizeof(*&a));//&a是数组的地址,是数组指针类型,*&a是都数组指针解引用,访问一个数组的大小
	//16字节
	//sizeof(*&a) ==> sizeof(a)  =16
	
	printf("%d\n", sizeof(&a + 1));//&a数组的地址,&a+1跳过整个数组,&a+1还是地址,是 4/8 个字节
	printf("%d\n", sizeof(&a[0]));//a[0]是数组的第一个元素,&a[0]是第一个元素的地址,是 4/8 个字节
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一个元素的地址,&a[0]+1就是第二个元素的地址,是 4/8 个字节

	//&a[0] - int*
	//&a[0]+1 -> &a[1]

	return 0;
}

字符数组

int main() {
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", strlen(arr));//随机值,arr是数组名,但是没有放在sizeof内部,也没&,arr就是首元素的地址
	//strlen得到arr后,从arr数组首元素的地方开始计算字符串的长度,直到直到\0,但是arr数组中没有\0,arr内存的后边是否有\0,在什么位置
	//是不确定的,所以\0之前出现了多少个字符是随机的。
	//
	printf("%d\n", strlen(arr + 0));//arr是数组首元素的地址,arr+0还是首元素的地址
	//随机值

	//printf("%d\n", strlen(*arr));//arr是数组首元素的地址,*arr 是首元素 - ‘a’ - 97
	//strlen就把‘a’的ASCII码值 97 当成了地址
	//err 会非法访问内存
	 
	//printf("%d\n", strlen(arr[1]));//arr[1] - 'b' - 98 - err

	printf("%d\n", strlen(&arr));//随机值,&arr是数组的地址,数组的地址也是指向数组起始位置,和第一个案例一样
	printf("%d\n", strlen(&arr + 1));//&arr + 1表示跳过这个数组,随机值
	printf("%d\n", strlen(&arr[0] + 1));//第二个元素的地址,也是随机值

	//printf("%d\n", sizeof(arr));//arr是数组名,并且是单独放在sizeof内部,计算的是数组总大小,单位是字节 - 6
	//printf("%d\n", sizeof(arr + 0));//arr是数组名,并非单独放在sizeof内部,arr表示首元素的地址,arr+0还是首元素的地址
	是地址大小就是4/8
	//
	printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,sizeof计算的是首元素的大小,是1字节
	printf("%d\n", sizeof(arr[1]));//arr[1]是数组的第二个元素,sizeof(arr[1])计算的是第二个元素的大小,1个字节
	printf("%d\n", sizeof(&arr));//&arr- 取出的是数组的地址,sizeof(&arr))计算的是数组的地址的大小,是地址就是4/8字节
	printf("%d\n", sizeof(&arr + 1));//&arr是数组的地址,&arr+1跳过整个数组,指向'f'的后边,&arr+1的本质还是地址,是地址就是4/8字节
	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是‘a’的地址,&arr[0]+1是'b'的地址,是地址就是4/8字节
	//&arr[0] - char*
}

字符常量数组

arr是存在栈上的数组,数据来自代码段的拷贝

int main()
{
	char arr[] = "abcdef";

	//char ch = 'w';
	//int* pc = &ch;//char*

	printf("%d\n", strlen(arr));       // 6
	printf("%d\n", strlen(arr + 0));    //6  从a开始数
	printf("%d\n", strlen(*arr));        //报错  把a的ascll码当地址传过去
	printf("%d\n", strlen(arr[1]));       // 报错
	printf("%d\n", strlen(&arr));         //   6 &arr是数组的地址,数组的地址也是指向数组起始位置
	printf("%d\n", strlen(&arr + 1));     //   随机
	printf("%d\n", strlen(&arr[0] + 1));    //    5

	//printf("%d\n", sizeof(arr));         7
	//printf("%d\n", sizeof(arr + 0));    //arr是数组首元素的地址,arr+0还是首元素的地址:4/8
	//printf("%d\n", sizeof(*arr));        1
	//printf("%d\n", sizeof(arr[1]));        1
	//printf("%d\n", sizeof(&arr));        4/8
	//printf("%d\n", sizeof(&arr + 1));        4/8
	//printf("%d\n", sizeof(&arr[0] + 1));     4/8

	return 0;
}

字符串常量

p用const修饰,在栈上,存储的是代码段常量字符串的首地址
在这里插入图片描述


int main()
{
	const char* p = "abcdef";
	const char** pp = &p;

	printf("%d\n", strlen(pp));						// 6

	printf("%d\n", strlen(p));						// 6
	printf("%d\n", strlen(p + 1));					// 5
	//printf("%d\n", strlen(*p));					//错误,把a的ASCLL码当成地址
	//printf("%d\n", strlen(p[0]));					//错误,同上

	//strlen(&p)并不是一个有效的操作。&p得到的是指向指针变量p的指针,也就是一个指向指针的指针,
	//而strlen需要的是一个指向有效字符串的指针。所以,这可能会导致未定义的行为
	printf("%d\n", strlen(&p));						//随机值 &p是在p的那块内存往后找\0,位置不确定
	printf("%d\n", strlen(&p + 1));					//随机值 同上
	printf("%d\n", strlen(&p[0] + 1));				//5

	printf("%zu\n", sizeof(p));						//   4/8
	printf("%zu\n", sizeof(p + 1));					//   4/8
	printf("%zu\n", sizeof(*p));					//   1          *p==*(p+0)==p[0]
	printf("%zu\n", sizeof(p[0]));					//   1
	printf("%zu\n", sizeof(&p));					//   4/8
	printf("%zu\n", sizeof(&p + 1));				//   4/8
	printf("%zu\n", sizeof(&p[0] + 1));				//   4/8

	return 0;
}

二维数组

int main()
{
	//二维数组
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//a是二维数组的数组名,数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
	//48
	printf("%d\n", sizeof(a[0][0]));//a[0][0]是一个整型元素,大小是4个字节
	printf("%d\n", sizeof(a[0]));//把二维数组的每一行看做一维数组的时候,a[0]是第一行的数组名,第一行的数组名单独放在sizeof内部
	//计算的是第一行的总大小,单位是字节 - 16
	printf("%d\n", sizeof(a[0] + 1));//a[0]虽然是第一行的数组名,但是并非单独放在sizeof内部
	//a[0]作为第一行的数组名并非表示整个第一行这个数组,a[0]就是第一行首元素的地址,a[0]--> &a[0][0] - int*
	//a[0]+1,跳过一个int,是a[0][1]的地址  4/8字节
	printf("%d\n", sizeof(*(a[0] + 1)));//a[0]+1是第一行第二个元素的地址,所以*(a[0]+1)就是a[0][1],大小是4个字节
	
	printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,没单独放在sizeof内部,也没有&,所以a就是数组首元素的地址
	//二维数组,我们把它想象成一维数组,它的第一个元素就是二维数组的第一行
	//a就是第一行的地址,a+1 是第二行的地址,是地址,大小就是 4/8 个字节
	//a - &a[0]
	//a+1 - &a[1]
	//a+2 - &a[2]

	printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,*(a+1) 找到的就是第二行,sizeof(*(a + 1))计算的就是第二行的大小
	//16
	//*(a+1) --> a[1]
	//sizeof(*(a + 1)) --> sizeof(a[1])
	//
	printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0]+1就是第二行的地址,sizeof(&a[0] + 1)计算的第二行地址大小
	//单位是字节 - 4/8

	printf("%d\n", sizeof(*(&a[0] + 1)));//&a[0] + 1是第二行的地址,*(&a[0] + 1)拿到的就是第二行,大小就是16个字节
	//*(&a[0]+1) --> a[1]

	printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址 - &a[0]
	//*a - 拿到的就是第一行 - 大小就是16个字节
	//*a -> *(a+0) -> a[0]
	//
	printf("%d\n", sizeof(a[3]));//代码没问题
	//a[3]是二维数组的第4行,虽然没有第四行,但是类型能够确定,大小就是确定的。大小就是一行的大小,单位是字节 - 16
	//能够分析出 a[3]的类型是:int [4]
	// 
	//任何一个表达式有2个属性
	//3+5
	//值属性:8
	//类型属性:int

	return 0;
}

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

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

相关文章

向量的概念、向量组的概念

目录 向量的概念、向量组的概念 向量的基本运算 线性表出、线性相关、线性无关 向量的概念、向量组的概念 向量(Vector)是一个有次序的数所组成的数组,通常用来表示一个物理量或者一个对象在空间中的移动。向量可以表示位置、速度、力等物…

竞赛 基于机器视觉的手势检测和识别算法

0 前言 🔥 优质竞赛项目系列,今天要分享的是 基于深度学习的手势检测与识别算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng…

蓝牙核心规范(V5.4)12.2-深入详解之加密广播数据(Encrypted Advertising Data)

蓝牙篇之蓝牙核心规范(V5.4)深入详解汇总 1.知识回顾 1.1 带响应的周期广播 在上一节已经讲了。 1.2 广播结构体 蓝牙核心规范定义了广播数据(AD)结构。它是一个用于包含在蓝牙LE广告和扫描响应数据包中以及在蓝牙BR/EDR扩展查询响应(EIR)数据包中的一般容器。包含在A…

nvm 一个nodejs版本管理工具

nvm 一个nodejs版本管理工具 NVM是什么 nvm全英文也叫node.js version management,是一个nodejs的版本管理工具。nvm和n都是node.js版本管理工具,为了解决node.js各种版本存在不兼容现象可以通过它可以安装和切换不同版本的node.js NVM下载 可在点此在…

长城靶场溯源第四题

先统计访问的ip 直到第一个包过滤到202.1.1.2 很明显的一句话木马,就是他了,202.1.1.2 卡描述:2.服务器1.99的web服务器使用的CMS及其版本号(请直接复制) 继续查看同一个数据包,发现个奇奇怪怪的phpinf…

python flask框架接受axios发送的图片文件

文章目录 前端部分axios配置请求部分代码页面代码 后端代码结果 前端部分 axios配置 主要是一些基础的配置,这里可看可不看,主要的不是这里 import axios from axios; let baseURL /demo// 创建axios实例 const service axios.create({// axios中请…

山洪灾害预警方案(山洪预警解决方案的组成)

​ 随着气候变化的不断加剧,山洪灾害在许多地区成为了极具威胁性的自然灾害之一。为了帮助地方政府和居民更好地预防和应对山洪灾害,我们设计了一套基于星创易联的SR600工业路由器和DTU200的山洪灾害预警方案,并成功在某地区进行了部署。 案…

【Linux从入门到精通】线程 | 线程介绍线程控制

本篇文章主要对线程的概念和线程的控制进行了讲解。其中我们再次对进程概念理解。同时对比了进程和线程的区别。希望本篇文章会对你有所帮助。 文章目录 一、线程概念 1、1 什么是线程 1、2 再次理解进程概念 1、3 轻量级进程 二、进程控制 2、1 创建线程 pthread_create 2、2…

代码随想录算法训练营第49天|121. 买卖股票的最佳时机,买卖股票的最佳时机II

链接: 121. 买卖股票的最佳时机 链接: 122.买卖股票的最佳时机II 121. 买卖股票的最佳时机 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出…

代码托管的力量:构建协作、追踪和持续交付的软件开发生态系统

💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 引言 在现代软件开发中…

浅析-vue.js

学习目标 会创建Vue实例,知道Vue的常见属性会使用Vue的生命周期的钩子函数会使用vue常见指令会使用vue计算属性和watch监控会编写Vue组件掌握组件间通信了解vue-router使用了解webpack使用会使用vue-cli搭建项目 0.前言 前几天我们已经对后端的技术栈有了初步的了…

Spark_Spark内存模型管理

工作中经常用到Spark内存调参,之前还没对这块记录,这次记录一下。 环境参数 spark 内存模型中会涉及到多个配置,这些配置由一些环境参数及其配置值有关,为防止后面理解混乱,现在这里列举出来,如果忘记了&a…

冠达管理:庄家最怕的8个方法?

在股票商场上,庄家总是短时刻内操控价格,并在一定的时刻内进出股市,以赚取巨额赢利。 假如想在股票商场上盈余,那么就必须站在庄家的对立面,把握一些防护和反击的办法。这里就来介绍一些庄家最怕的办法。 一、技能剖析…

恒运资本:沪指震荡涨0.28%,医药板块强势拉升,金融等板块上扬

15日早盘,沪指盘中震荡上扬,科创50指数表现强势;北向资金小幅净流入。 到午间收盘,沪指涨0.28%报3135.31点,深成指、创业板指涨均0.11%,科创50指数涨1.04%;两市合计成交4357亿元,北…

Java基础语法之数组

💕十年生死两茫茫,不思量,自难忘💕 作者:Mylvzi 文章主要内容:Java学习之--数组 一.数组的基本概念 1.定义 数组是相同数据类型的集合!使用数组来存放多个相同类型的数据! 2.Jav…

亚马逊云科技打造SAP核心业务系统上云最佳实践,加快业务转型和价值实现

数字化转型步入深水区,企业竞争日益激烈,乘云而上、快速进行现代化转型和创新,才能不断紧跟趋势变化,实现「高质量发展」。作为亚马逊云科技全球战略合作伙伴,SAP和亚马逊云科技的联合创新已超过15年,双方共…

持续深耕金融科技领域,神策数据正式加入证券基金行业信创联盟

近日,神策数据正式加入证券基金行业信息技术应用创新联盟(简称“信创联盟”),携手更多行业力量,促进证券基金行业信创关键技术研究、应用和服务。 证券基金信创联盟由上交所联合行业券商倡议发起成立,由证监…

【计算机视觉 | 图像模型】常见的计算机视觉 image model(CNNs Transformers) 的介绍合集(十)

文章目录 一、GreedyNAS-A二、ASLFeat三、GreedyNAS-B四、Twins-PCPVT五、MoGA-A六、MoGA-C七、Visformer八、Multi-Heads of Mixed Attention九、LocalViT十、SPP-Net十一、The Ikshana Hypothesis of Human Scene Understanding Mechanism十二、DetNASNet十三、TResNet十四、…

thinkphp:查询本周中每天中日期的数据

以今天2023-09-14为例,这一周为2023-09-11~2023-09-07 运行结果 结果: 代码 后端thinkphp: //查询本周每天的的总金额数 //获取本周的起始日期和结束日期 $weekStart date(Y-m-d, strtotime(this week Monday)); $weekEnd date(Y-m-d, strtotime(t…

【Vue】大悟!模板语法-插值语法指令语法

模板语法 Vue模板语法包括两大类 插值语法 插值语法也就是两个大括号,也叫Mustache 功能:用于解析标签体内容,可以进行运算、三元表达式等,将最终解析出来的内容插入到标签中 写法:{{xxx}},xxx 是 js 表达式&…