C语言:指针和数组(看完拿捏指针和数组)
目录
数组名的理解:
一维数组:
解析:
字符数组:
解析:
解析:
字符串数组:
解析:
解析:
一级指针:
解析:
解析:
二维数组:
解析:
指针笔试题:
题一:一维数组
题二: 结构体指针
题三: 一维数组
题四: 二维数组
题五: 二维数组
题六: 二维数组
题七:指针数组
题八: 指针数组(多级)
以上就是个人学习见解和学习的解析,欢迎各位大佬在评论区探讨!
感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!
数组名的理解:
数组名是数组首元素的地址;
但是有2个例外:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节;
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
代码中的4/8指的是在32位或者X86环境下位4个字节,在X64环境下是8个字节。
一维数组:
#include <stdio.h>
int main()
{int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));//16printf("%d\n", sizeof(a + 0));//4/8printf("%d\n", sizeof(*a));//4printf("%d\n", sizeof(a + 1));//4/8printf("%d\n", sizeof(a[1]));//4printf("%d\n", sizeof(&a));//4/8printf("%d\n", sizeof(*&a));//16printf("%d\n", sizeof(&a + 1));//4/8printf("%d\n", sizeof(&a[0]));//4/8printf("%d\n", sizeof(&a[0] + 1));//4/8return 0;
}
解析:
1、sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2、a不是单独放在sizeof()内部,也没有取地址,所以a就是首元素的地址,a+0还是首元素的地址,是地址大小就是4/8个字节。
3、*a中的a是数组首元素的地址,*a就是对首元素的地址解引用,找到的就是首元素,首元素的大小就是4个字节。
4、这里的a是数组首元素的地址,a+1是第二个元素的地址,sizeof(a+1)就是地址的大小
5、计算的是第二个元素的大小。
6、&a取出的数组的地址,数组的地址也就是个地址。
7、&a----> int( * )[ 4 ], *&a----->int [ 4 ]。
8、&a取出的是数组的地址,&a--> int( * )[ 4 ],&a+1是从数组a的地址向后跳过一个(4个整型元素)数组的大小,&a+1还是地址,是地址就是4/8个字节。
9、&a[ 0 ]就是第一个元素的地址,计算的是地址的大小,是地址就是4/8个字节。
10、&a[ 0 ]+1就是第二个元素的地址,大小是4/8个字节,&a[ 0 ]+1---> &a[ 1 ] 。
字符数组:
#include <stdio.h>int main()
{char arr[] = {'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));//6printf("%d\n", sizeof(arr+0));//4/8printf("%d\n", sizeof(*arr));//1printf("%d\n", sizeof(arr[1]));//1printf("%d\n", sizeof(&arr));//4/8printf("%d\n", sizeof(&arr+1));//4/8printf("%d\n", sizeof(&arr[0]+1));//4/8return 0;
}
解析:
1、//数组名单独放在sizeof内部,这里的arr表示整个数组,计算的是整个数组的大小,单位是字节,总共6个字节类型是char [6]。
2、//arr表示数组首元素的地址,arr+0还是数组首元素的地址,是地址就是4/8个字节,类型是char*。
3、//arr表示数组首元素的地址,*arr就是首元素,大小1个字节,类型是char。
4、//arr[1]就是第二个元素,大小是1个字节。
5、//&arr是数组的地址,但是数组的地址也是地址,是地址就是4/8。
6、//&arr + 1是跳过整个数组后的地址,是地址就是4/8个字节。
7、//第二个元素的地址,是4/8个字节。
#include <stdio.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;
}
解析:
1、因为字符数组arr中没有‘ \0 ’,所以在求字符串长度的时候,会一直往后找,产生的结构就是随机值。
2、arr + 0是首元素的地址,和第一个一样,也是随机值。
3、//错误, arr是数组首元素的地址,*arr就是数组首元素,就是'a'-97;
//strlen函数参数的部分需要传一个地址,当我们传递的是'a'时,'a'的ASCII码值是97,那就是将97作为地址传参。
//strlen就会从97这个地址开始统计字符串长度,这就非法访问内存了。4、//错误
5、//&arr是数组的地址,数组的地址和数组首元素的地址,值是一样的,那么传递给strlen函数后,依然是从数组的第一个元素的位置开始往后统计。
6、//随机值
7、//&arr[0] + 1是第二个元素的地址。结果也是随机值。
字符串数组:
#include <stdio.h>int main()
{char arr[] = "abcdef";// a b c d e f \0printf("%d\n", sizeof(arr));//7printf("%d\n", sizeof(arr+0));//4printf("%d\n", sizeof(*arr));//1printf("%d\n", sizeof(arr[1]));//1printf("%d\n", sizeof(&arr));//4/8printf("%d\n", sizeof(&arr+1));//4/8printf("%d\n", sizeof(&arr[0]+1));//4/8return 0;
}
解析:
1、//7,类型是char [7]。
2、//arr + 0是首元素的地址。
3、//*arr其实就是首元素,1个字节,理解为*arr--> *(arr+0) -- arr[0]。
4、//arr[1]是第二个元素,1个字节。
5、//&arr是数组的地址,是地址就是4/8个字节。
6、//&arr + 1是跳过一个数组的地址,4/8。
7、//&arr[0] + 1是第二个元素的地址 4/8。
#include <stdio.h>int main()
{char arr[] = "abcdef";printf("%d\n", strlen(arr));//6printf("%d\n", strlen(arr+0));//6printf("%d\n", strlen(*arr));//错误printf("%d\n", strlen(arr[1]));//错误printf("%d\n", strlen(&arr));//6printf("%d\n", strlen(&arr+1));//随机值printf("%d\n", strlen(&arr[0]+1));//5return 0;
}
解析:
由于与上面内容相同,就不做过多解释
1、//6
2、//6
3、//err
4、//err
5、//6
6、//随机值
7、//5
一级指针:
#include <stdio.h>int main()
{char *p = "abcdef";printf("%d\n", sizeof(p));//4/8printf("%d\n", sizeof(p+1));//4/8printf("%d\n", sizeof(*p));//1printf("%d\n", sizeof(p[0]));//1printf("%d\n", sizeof(&p));//4/8printf("%d\n", sizeof(&p+1));//4/8printf("%d\n", sizeof(&p[0]+1));//4/8return 0;
}
解析:
1、//p是一个指针变量,大小就是4/8。
2、//p+1是'b'的地址,是地址大小就是4/8个字节。
3、//*p 就是'a'元素,就是1个字节。
4、//p[0]--> *(p+0) --> *p 1个字节。
5、//4/8,类型是&p -- char**。
6、//4/8
7、//4/8 , &p[0] + 1得到是'b'的地址 。
#include <stido.h>int main()
{char *p = "abcdef";printf("%d\n", strlen(p));//6printf("%d\n", strlen(p+1));//5printf("%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));//5return 0;
}
解析:
由于与上面内容相同,就不做过多解释
1、//6
2、//5
3、//err
4、//err
5、//随机值
6、//随机值
7、//5
二维数组:
#include <stdio.h>int main()
{int a[3][4] = {0};printf("%d\n",sizeof(a));//48printf("%d\n",sizeof(a[0][0]));//4printf("%d\n",sizeof(a[0]));//16printf("%d\n",sizeof(a[0]+1));//4/8printf("%d\n",sizeof(*(a[0]+1)));//4printf("%d\n",sizeof(a+1));//4/8printf("%d\n",sizeof(*(a+1)));//16printf("%d\n",sizeof(&a[0]+1));//4/8printf("%d\n",sizeof(*(&a[0]+1)));//16printf("%d\n",sizeof(*a));//16printf("%d\n",sizeof(a[3]));//16return 0;
}
解析:
1、//3*4*4 = 48
2、//4
3、//a[0]是第一行这个一维数组的数组名,数组名算是单独放在sizeof内部了,计算的是整个数组的大小,大小是16个字节。
4、//a[0]作为第一行的数组名,没有单独放在sizeo内部,没有&,a[0]表示数组首元素的地址,也就是a[0][0]的地址,所以a[0]+1是第一行第二个元素的地址,是地址就是4/8个字节。
5、//4,计算的是就是第一行第2个元素的大小。
6、//4 / 8,a是数组首元素的地址,是第一行的地址 int(*)[4],a+1 就是第二行的地址。
7、//16,*(a+1) --> a[1] -> sizeof(*(a+1))->sizeof(a[1]) 计算的是第二行的大小,a+1 --> 是第二行的地址,int(*)[4],*(a+1) 访问的第二行的数组。
8、//4/8,&a[0]是第一行的地址 int(*)[4],&a[0]+1 是第二行的地址 int(*)[4]。
9、//16 计算的是第二行的大小。
10、//计算的是第一行的大小-16,a是数组首元素的地址,就是第一行的地址,*a 就是第一行,*a --> *(a+0) --> a[0]。
11、//16,类型是a[3]--> int [4]。
指针笔试题:
题一:一维数组
#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;
}
注意:&a+1的类型为int( * )[ 5 ],强制转换为int( * ).此时每次移动的就是4个字节,而不是20个字节了!
题二: 结构体指针
#include <stdio.h>
//由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}
注意:整型就是正常的加减运算,指针类型就需要加减n*类型的大小。
题三: 一维数组
#include <stdio.h>int main()
{int a[4] = { 1, 2, 3, 4 };int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1);printf( "%x,%x", ptr1[-1], *ptr2);return 0;
}
注意: a强制转换成int类型+1就是正常加减,最后转换为指针int计算机会向后查找四个字节。
题四: 二维数组
#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;
}
注意: 注意二维数组中没有用{ }把数值包含,这里用的是( )是逗号表达式,取最后一个值为元素;a[ 0 ]可以看做&a[ 0 ][ 0 ].
题五: 二维数组
#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;
}
注意:地址相减为相差的元素个数 ,此题为-4,因为求的是地址,所以需要将-4转换成补码输出。
题六: 二维数组
#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;
}
注意:*(aa+1) = a[1] = &a[1][0]。
题七:指针数组
#include <stdio.h>int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}
注意:这里的a是指针数组,数组中每个位置的类型为char*。
题八: 指针数组(多级)
#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;
}
注意:有了上面的基础,这道题一步一步来,你们也可以解释清楚!!!
以上就是个人学习见解和学习的解析,欢迎各位大佬在评论区探讨!
感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!
相关文章:

C语言:指针和数组(看完拿捏指针和数组)
目录 数组名的理解: 一维数组: 解析: 字符数组: 解析: 解析: 字符串数组: 解析: 解析: 一级指针: 解析: 解析: 二维数组&a…...

Conda命令整理-自用版
Conda用法整理-自用版 Conda介绍1、环境操作1.1 创建环境1.2 激活环境1.3 导出环境1.4 导入环境1.5 关闭环境1.6 删除环境 2、包操作2.1 安装软件包2.2 安装指定包的指定版本 参考资料 Conda介绍 Conda是一个开源的包管理系统和环境管理器,用于在不同的计算环境中安…...

CountDownLatch 和 CyclicBarrier的区别与详解
文章目录 一.CountDownLatch 和 CyclicBarrier的区别二.详解总结用法CountDownLatch 用法CyclicBarrier 用法 一.CountDownLatch 和 CyclicBarrier的区别 CountDownLatch和CyclicBarrier都是线程同步的工具类,都是基于AQS实现的;CountDownLatch 的计数器…...

Vue子组件向父组件传值(this.$emit()方法)
子组件使用this.$emit()向父组件传值 首先必须在父组件中引用子组件,然后实现传值 第一步 在父组件中引入子组件 使用import引入组件 import indexImportOrder from ./components/indexImportOrder 声明 //定义组件components:{indexImportOrder,}, 使用 &l…...

【C++】C/C++内存管理-new、delete
文章目录 一、C/C内存分布二、C/C中动态内存管理方式2.1 C语言中动态内存管理方式2.2 C内存管理方式 三、operator new和operator delete函数3.1 operator new和operator delete函数3.2 operator new与operator delete的类专属重载(了解) 四、new和delet…...

高手进阶之路---pyqt自定义信号
高手进阶之路—pyqt自定义信号 1.思考问题为什么要自定义信号,qt5本身已有信号槽函数 # pushButton 被clicked的时候connect 函数print self.pushButton.clicked.connect(self.print)def print(self):print("我被点击了")或者使用 # 需要引入 pyqtSlo…...

研磨设计模式day09原型模式
目录 场景 代码实现 有何问题 解决方案 代码改造 模式讲解 原型与new 原型实例与克隆出来的实例 浅度克隆和深度克隆 原型模式的优缺点 思考 何时选用? 相关模式 场景 代码实现 定义订单接口 package com.zsp.bike.day08原型模式;/*** 订单的接口*…...

(二)Redis——List
因为是 List,所以所有相关的命令都以 L 开头。 LPUSH / RPUSH LRANGE list 0 -1 -1 表示末尾 127.0.0.1:6379> LPUSH list a 1 127.0.0.1:6379> LRANGE list 0 -1 a 127.0.0.1:6379> LPUSH list b 2 127.0.0.1:6379> LRANGE list 0 -1 b a 127.0.0.…...

【Go Web 篇】Go 语言进行 Web 开发:构建高性能网络应用
随着互联网的快速发展,Web 开发已经成为了软件开发领域中不可或缺的一部分。随之而来的是对于更高性能、更高效的网络应用的需求。在这个领域,Go 语言因其并发性能、简洁的语法以及丰富的标准库而备受关注。本篇博客将深入探讨如何使用 Go 语言进行 Web …...

开悟Optimization guide for intermediate tracks
目录 认识模型 参考方案(按模块拆解) 认识模型 模型控制1名英雄进行镜像1 v 1对战 Actor集群资源为64核CPU 问题特点:单一公平对抗场景(同英雄镜像对赛),单位时间样本产能低,累计训练资源相…...

wx.request配置服务器域名,只能包含英文大小写字母、数字,解决办法
前言.小程序服务器域名配置常见错误及解决方法 1.配置入口: 小程序后台->-开发->开发设置->服务器域名 2.常见错误及原因分析: 3.实战中出现的错误 4.解决办法:应把域名后边的路径去掉,只写域名即可...

【有效的括号】
题目 1、左括号入栈 2、右括号出栈顶括号进行匹配 栈 typedef char STDataType; //元素为char类型 typedef struct Stack {STDataType* a;//动态的开辟空间int top;int capacity; }ST;void StackInit(ST* ps)//初始化 {assert(ps);ps->a (STDataType*)malloc(sizeof(STD…...

积跬步至千里 || 数学基础、算法与编程
数学基础、算法与编程 1. BAP 技能 BAP 技能是指基础(Basic)、算法(Algorithm)和编程(Programm)三种基本技能的深度融合。理工科以数学、算法与编程为根基,这三个相辅相成又各有区别。 (1)数学以线性代数为主要研究工具和部分微积分技术为手…...

Java单元测试 JUnit 5 快速上手
一、背景 什么是 JUnit 5?首先就得聊下 Java 单元测试框架 JUnit,它与另一个框架 TestNG 占据了 Java领域里单元测试框架的主要市场,其中 JUnit 有着较长的发展历史和不断演进的丰富功能,备受大多数 Java 开发者的青睐。 而说到…...

【Linux网络】TCP UDP socket HTTP webSocket之间的区别
目录 一、OSI & TCP/IP模型 二、几者之间的关系 三、HTTP 四、Socket 五、WebSocket 5.1、WebSocket 优点 一、OSI & TCP/IP模型 首先我们要了解OSI七层模型,和预支对应的TCP/IP 四层的模型。 用下面的图可以看出,TCP UDP 工作在传输层&…...

【面向大一新生IT技术社群招新啦,不来瞅瞅?】
个人名片: 🐼作者简介:一名大三在校生 🐻❄️个人主页:落798. 🐼个人WeChat:落798. 🕊️系列专栏:【零基础学java】 ----- 【重识c语言】 ---- 【计算机网络】—【Spri…...

分析系统 - 使用Python爬虫
在竞争激烈的市场环境中,了解和分析竞争对手的销售策略和市场表现对于企业的成功至关重要。本文将介绍如何利用Python爬虫建立低成本的销售竞争对手分析系统,探索其方法、工具和好处,并同时解决可能出现的问题。 销售竞争对手分析的目标是获取…...

strstr函数
目录 函数介绍: 函数分析: 使用案例: 函数介绍: 返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。 匹配过程不包括终止空字符,但它到此为止。 …...

[C++] string类常用接口的模拟实现
文章目录 1、前言2、遍历2.1 operator[ ]下标方式2.2 迭代器2.3 范围for2.4 c_str 3、容量相关3.1 size(大小)3.2 capacity(容量)3.3 empty(判空)3.4 clear(清理)3.5 reserve3.6 res…...

每日一学——防火墙
防火墙是网络安全的重要组成部分,可以帮助保护网络免受恶意攻击和未经授权的访问。以下是防火墙的基本配置步骤: 定义安全策略:防火墙通过安全策略来决定允许或拒绝网络流量。你需要定义适当的安全策略来保护你的网络。安全策略通常包括源IP地…...

常用数据库备份方法,sql数据库备份方法
在信息时代,数据成为了公司的主要资产。然而,数据的安全性和完整性也成为企业管理的重要组成部分。因此,数据库备份至关重要。本文将详细介绍几种常见的数据库备份方法。 全备份 全备份是指数据库中所有数据的备份,包括数据文件、…...

常见前端面试之VUE面试题汇总八
22. Vue 子组件和父组件执行顺序 加载渲染过程: 1.父组件 beforeCreate 2.父组件 created 3.父组件 beforeMount 4.子组件 beforeCreate 5.子组件 created 6.子组件 beforeMount 7.子组件 mounted 8.父组件 mounted 更新过程: 1. 父组件 befor…...

弯道超车必做好题集锦二(C语言选择题)
前言: 编程想要学的好,刷题少不了,我们不仅要多刷题,还要刷好题!为此我开启了一个弯道超车必做好题锦集的系列,每篇大约10题左右。此为第二篇选择题篇,该系列会不定期更新,后续还会…...

PROFIBUS主站转MODBUS TCP网关
1.产品功能 YC-DPM-TCP网关在Profibus总线侧实现主站功能,在以太网侧实现ModbusTcp服务器功能。可将Profibus DP从站接入到ModbusTcp网络;通过增加DP/PA耦合器,也可将Profibus PA从站接入ModbusTcp网络。YC-DPM-TCP网关最多支持125个Profibu…...

【力扣】盛最多水的容器
目录 题目 题目初步解析 水桶效应 代码实现逻辑 第一步 第二步 第三步 代码具体实现 注意 添加容器元素的函数 计算迭代并且判断面积是否是最大值 总代码 运行结果 总结 题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是…...

【SQL应知应会】索引(三)• MySQL版:聚簇索引与非聚簇索引;查看索引与删除索引;索引方法
欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享,与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习,有基础也有进阶,有MySQL也有Oracle 索引 • MySQL版 前言一、索引1.简介2.索引类型之逻…...

rtmp直播
技术要求:nginxnginx-rtmpffmpegVLC 跟着大佬走的: 传送门 准备工作: 首先需要一台公网ip的服务器 这是使用天翼云的弹性云主机:免费试用1个月 天翼云官网 点击关机,更多里面选择重置密码, 默认用户名为…...

4.14 tcp_tw_reuse 为什么默认是关闭的?
开启 tcp_tw_reuse 参数可以快速复用处于 TIME_WAIT 状态的 TCP 连接时,相当于缩短了 TIME_WAIT 状态的持续时间。 tcp_tw_reuse 是什么? TIME_WAIT 状态的持续时间是 60 秒,这意味着这 60 秒内,客户端一直会占用着这个端口。端…...

Python数据分析和爬虫:解析数据的强大工具
引言: 在当今数据爆炸的时代,数据分析和数据提取变得越来越重要。作为一种简洁而强大的编程语言,Python在数据分析和爬虫领域有着广泛的应用。本文将详细介绍Python在数据分析和爬虫中的常用库和技术,并探讨其在实际应用中的优势…...

机器学习之SGD(Stochastic Gradient Descent,随机梯度下降)
SGD(Stochastic Gradient Descent,随机梯度下降)是深度学习中最基本的优化算法之一。它是一种迭代式的优化方法,用于训练神经网络和其他机器学习模型。以下是关于SGD优化器的重要信息: 基本原理:SGD的基本思…...