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

带你深层了解c语言指针

在这里插入图片描述

前言

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏: 🍔🍟🌯 c语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:介绍c语言中有关指针更深层的知识.
金句分享:

✨今天所有的混乱与芜杂,努力与精进,✨
✨都将在进步中变得更加清晰.✨

目录

  • 前言
  • 一、字符指针
  • 二、指针数组
    • 1.1 指针数组的定义
    • 2.2 使用指针数组模拟二维数组
  • 三、数组指针
  • 四、一维数组的传参
    • 4.1 整形一维数组传参:
    • 4.2 一维指针数组传参
  • 五、二维数组传参
    • 二级指针作为参数

一、字符指针

我们可以定义一个字符指针,指向一个字符变量,并通过指针来修改这个字符变量.

#include <stdio.h>
int main()
{char a = 'x';char* p = &a;*p = 'y';//通过指针来修改printf("%c\n", *p);printf("%c", a);return 0;
}

那么字符指针还可以怎么用呢?

下面这段代码的运行结果是什么呢?

int main()
{char* s1 =  "aabbccdd" ;for (int i = 0; i < 3; i++){*(s1 + i) = '0';}printf("%s", s1);return 0;
}

在这里插入图片描述
答案:

运行错误,原因是"aabbccdd"是常量字符串,它们存放在"常量区"(里面的东西是只读的),是不允许被修改的.

分析:

这段代码是将常量字符串存放进s1指针里面了吗?
显然不可能,想放也放不进去呀.
正确理解是:将该常量字符串的首元素放进了s1,即s1指向该字符串的首元素.

const关键字在后续的库函数模拟中会详细介绍,这里可以理解为被修饰的字符指针指向的内容,使其不能被修改.

使用字符指针打印字符串

int main()
{const char* s1 =  "aabbccdd" ;printf("%s", s1);return 0;
}

如果对上面的代码还是不理解可以看一下,下面的这一道曾经的笔试题:

#include <stdio.h>
int main()
{char str1[] = "你好,初阶牛!.";char str2[] = "你好,初阶牛!";const char* str3 = "你好,初阶牛!";const char* str4 = "你好,初阶牛!";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

在这里插入图片描述
答案:

str1 and str2 are not same
str3 and str4 are same

原因分析:

str1和str2是两个的字符数组,两个数组是相互独立的,它们在创建时,会各自向内存申请空间,所以地址必然不一样,只不过是在内存中两块不同内存区域存放着相同的内容罢了.
由于字符串常量是不能修改的,在内存中这类常量并没有必要保存两份,他们存储在内存中的常量区(只读型)所以str3和str4指向的是同一块空间.

图解:
在这里插入图片描述

二、指针数组

1.1 指针数组的定义

指针数组数组还是指针?
答案是数组.
我们知道,

整形数组:存放整形的数组.
字符数组,:存放字符的数组.
浮点型数组:存放浮点型数据的数组,

	int arr1[] = { 1,2,3,4,5 };//整形数组char arrr2[] = "abcdef";//字符型数组double arr3[] = { 3.4,5.8,1.9 };//浮点型数组

那么用于存放指针数组自然被称为指针数组了.
那么下面哪个是指针数组?

	int* arr1[10];int(*arr2)[10];

由于" * “'(星号)的优先级要低于”[ ]"(中括号)

arr1指针数组: arr1先与[10]先结合,故arr1是指针数组
arr2数组指针: 由于括号的优先级更高,所以(*arr2)是指针,指向的对象是数组,故arr2是数组指针.

常见的指针数组:

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

2.2 使用指针数组模拟二维数组

#include <stdio.h>
int main()
{int arr1[4] = { 1,2,3,4 };int arr2[4] = { 2,3,4,5 };int arr3[4] = { 3,4,5,6 };int* arr[3] = { arr1,arr2,arr3 };for (int i = 0; i < 3; i++){for (int j = 0; j < 4; j++){printf("%d ", *(arr[i] + j));}printf("\n");}return 0;
}

arr1数组,arr2数组,arr3数组在内存中都有自己独立的内存空间,
我们将这三个一维数组的首元素地址放在一个新的指针的数组(arr)中,通过指针数组来访问这三个一维数组,效果就如同二维数组一样,但并不是真正的二维数组.
图解:
在这里插入图片描述
内存中存储的图:
在这里插入图片描述

三、数组指针

指向数组指针被称为数组指针.

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };int(*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p//指针p就是数组指针,指向arr数组return 0;
}

数组指针对于一维数组作用并不是很大,数组指针一般用于二维数组.
在二维数组传参时可以使用数组指针接收.

对于初学者,数组指针指针数组经常容易搞混.
试着分析下面这些代码的含义吧!

int arr[5];//1
int *arr1[10];//2
int (*arr2)[10];//3
int (*arr3[10])[5];//4

在这里插入图片描述

答案:

1.整形数组:一个包含5个整形元素的整形数组
2.指针数组:数组中包含十个元素,每个元素都是一个整形指针(int*).
3.数组指针:指向一个拥有十个元素的整形指针.
4.数组指针数组:arr3先与[10]结合,说明arr3是一个数组,
其次剩下的int(*)[5]是arr3数组中的元素,显然是数组的每个元素都是一个数组指针.故arr3是存放了10个指向有5个整形元素数组的数组指针数组.

四、一维数组的传参

4.1 整形一维数组传参:

整形一维数组传过来的arr的是数组首元素地址,即一个整形的地址.
整形变量的地址用一级整形指针接收或者同样用数组接收都行.

void test1(int arr[])//使用不指定具体大小的一维数组接收
{}
void test2(int arr[10])//使用具体大小的一维数组接收
{}
void test3(int *arr)//使用指针接收
{}

具体实现:

#include <stdio.h>
//使用同样一维数组接收
void test1(int arr[],int sz)//arr1
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}
//与test1一样的道理,用指定大小接收当然也没问题
void test2(int arr[5],int sz)//arr1
{}
//使用指针接收
void test3(int* arr,int sz)//arr1
{for (int i = 0; i < sz; i++){printf("%d ", *(arr+i));//等价于printf("%d ", arr[i]);}printf("\n");
}int main()
{int arr1[] = { 1,2,3,4,5 };int sz = sizeof(arr1) / sizeof(arr1[0]);test1(arr1,sz);test2(arr1,sz);test3(arr1,sz);return 0;
}

4.2 一维指针数组传参

这三种有一种是错误的.

void test4(int *arr[20])
{}
void test5(int* arr)
{}
void test6(int **arr)
{}

一维指针数组的数组名表示首元素的地址,而首元素是一个整形指针,一级(整形)指针的地址可以用二级指针接收.也可以用相同类型的一维指针数组接收.

#include <stdio.h>
//用整形指针数组接收整形指针数组
void test4(int* arr[3])
{for (int i = 0; i < 3; i++)//决定访问整形指针的个数{for (int j = 0; j < 4; j++)//决定使用整形指针向后访问整形元素的个数{printf("%d ", *(arr[i] + j));///等价于printf("%d ", arr[i][j]);}printf("\n");}printf("\n");
}
//错误,不能使用
void test5(int* arr)
{}
//用二级指针接收一维指针数组
void test6(int** arr)
{for (int i = 0; i < 3; i++)//决定访问整形指针的个数{for (int j = 0; j < 4; j++)//决定使用整形指针向后访问整形元素的个数{printf("%d ", *(*(arr+i) + j));//这种一般不好理解//等价于	printf("%d ", *(arr[i] + j));//等价于	printf("%d ", arr[i][j]);}printf("\n");}
}
int main()
{int arr1[4] = { 1,2,3,4 };int arr2[4] = { 2,3,4,5 };int arr3[4] = { 3,4,5,6 };int* arr[3] = { arr1,arr2,arr3 };test4(arr);test5(arr);test6(arr);
}

五、二维数组传参

给定一个二维整形数组:
二维数组的数组名代表首元素地址,即第一行的地址(int*[ ]);

int arr[2][4] = { {1,2,3,4 },{5,6,7,8} };

下面七种传参方式,哪些是正确的.

void test1(int arr[2][4])
void test2(int arr[][])
void test3(int arr[][4])
void test4(int *arr)
void test5(int* arr[4])
void test6(int (*arr)[4])
void test7(int **arr)

在这里插入图片描述

正确传参方式:test1()、test3()和test6()

#include <stdio.h>
void test1(int arr[2][4])
{int i = 0, j = 0;printf("test1\n");for (i = 0; i < 2; i++){for (j = 0; j < 4; j++){printf("%d ", arr[i][j]);}printf("\n");}printf("\n");
}
void test3(int arr[][4])
{int i = 0, j = 0;printf("test2\n");for (i = 0; i < 2; i++){for (j = 0; j < 4; j++){printf("%d ", arr[i][j]);}printf("\n");}printf("\n");
}
void test6(int(*arr)[4])//ok?
{int i = 0, j = 0;printf("test3\n");for (i = 0; i < 2; i++){for (j = 0; j < 4; j++){printf("%d ", arr[i][j]);}printf("\n");}printf("\n");
}
int main()
{int arr[2][4] = { {1,2,3,4 },{5,6,7,8} };test1(arr);test3(arr);test6(arr);
}

二级指针作为参数

二级指针可以接收一级指针的地址.

#include <stdio.h>
void print1(int** aa)
{printf("%d\n", **aa);
}
void print2(char** pp)
{printf("%c\n", **pp);
}
int main()
{int a = 5;int* aa = &a;char* p = "abcdef";char** pp = &p;print1(&aa);print2(&p);print2(pp);return 0;
}

指针进阶的内容比较多,本篇先讲到这里.
最后希望这篇文章对大家有些帮助.
感觉支持!!!💗💗💗

在这里插入图片描述

相关文章:

带你深层了解c语言指针

前言 &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; c语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨今天…...

2-MATLAB APP Design-下拉菜单栏的使用

一、APP 界面设计展示 1.新建一个空白的APP,在此次的学习中,我们会用到编辑字段(文本框)、下拉菜单栏、坐标区,首先在界面中拖入一个编辑字段(文本框),在文本框中输入内容:下拉菜单栏的使用,调整背景颜色,字体的颜色为黑色,字体的大小调为26. 2.在左侧组件库常用栏…...

七、HTTPTomcatServlet

1&#xff0c;Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网&#xff0c;也称为万维网(www)&#xff0c;能够通过浏览器访问的网站。 在我们日常的生活中&#xff0c;经常会使用浏览器去访问百度、京东、传智官网等这些网站&#xff0c;这些网站统称为Web网站。如下就是通…...

LeetCode 热题 C++ 198. 打家劫舍

力扣198 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋存…...

C语言学习笔记——程序环境和预处理

目录 前言 一、程序环境 1. 翻译环境 1.1 主要过程 1.2 编译过程 2. 运行环境 二、预处理 1. 预定义符号 2. #define 2.1 #define定义标识符 2.2 #define定义宏 2.3 命名约定和移除定义 3. 条件编译 4. 文件包含 结束语 前言 每次我们写完代码运行的时候都…...

「JVM 高效并发」Java 内存模型

Amdahl 定律代替摩尔定律成为了计算机性能发展的新源动力&#xff0c;也是人类压榨计算机运算能力的最有力武器&#xff1b; 摩尔定律&#xff0c;描述处理器晶体管数量与运行效率之间的发展关系&#xff1b;Amdahl 定律&#xff0c;描述系统并行化与串行化的比重与系统运算加…...

C语言刷题(2)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰来复习一下之前所学过的内容噢&#xff0c;复习的方式&#xff0c;那当然是刷题啦&#xff0c;现在&#xff0c;就让我们进入C语言的世界吧 当然&#xff0c;题目还是来源于牛客网 完完全全零基础 编程语言初学训练营_在线编程题…...

第一个 Spring MVC 注解式开发案例(初学必看)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

openresty学习笔记

openresty 简介 openresty 是一个基于 nginx 与 lua 的高性能 web 平台&#xff0c;其内部 集成了大量精良的 lua 库、第三方模块以及大数的依赖项。用于 方便搭建能够处理超高并发、扩展性极高的动态 web 应用、 web 服务和动态网关。 openresty 通过汇聚各种设计精良的 ngi…...

微信小程序DAY3

文章目录一、页面导航1-1、声明式导航1-2、编程式导航1-3、声明式导航传参1-4、编程式导航传参1-5、获取导航传递的参数二、页面事件2-1、下拉刷新事件2-1-1、启用下拉刷新2-1-2、配置下拉刷新2-1-3、监听页面下拉刷新事件2-2、上拉触底事件2-2-1、事件触发2-2-1、事件配置三、…...

【CAN】手把手教你学习CAN总线(一)

CAN总线一、CAN总线概念二、CAN的差分信号三、CAN总线的通信协议1、 帧起始2、仲裁段3、控制段4、数据段5、CRC段6、ACK段7、帧结束四、CAN的位时序1、同步段&#xff08;SS&#xff09;2、传播时间段&#xff08;PTS&#xff09;3、相位缓冲段&#xff08;PBS&#xff09;4、再…...

JUC 体系的基石——AQS

—— AQS&#xff08;AbstractQueuedSynchronizer&#xff09; 概念 抽象队列同步器&#xff1b;volatile cas 机制实现的锁模板&#xff0c;保证了代码的同步性和可见性&#xff0c;而 AQS 封装了线程阻塞等待挂起&#xff0c;解锁唤醒其他线程的逻辑。AQS 子类只需要根据状…...

Qt中信号与槽的使用

Qt中信号与槽的使用 Qt当中一个重要的东西是信号和槽&#xff0c;它被用于对象之间的通信。 在Qt中&#xff0c;例如“点击按钮”这个事件就是发送信号的对象&#xff0c;接收信号的是某一个窗口&#xff0c;响应信号的是一个处理&#xff0c;可以是隐藏窗口或者是关闭窗口。…...

力扣-销售员

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;607. 销售员二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他总结前言 …...

HTML综合案例练习

一、展示简历内容 可以首先看一下我们的效果&#xff0c;之后再思考怎么实现 总的来说&#xff0c;这个练习不算难。 这里关于这个简历的代码编写我们不说太多&#xff0c;只注意以下几个内容即可&#xff1a; 注意及时查看我们的代码是否符合预期&#xff0c;即一段一段测 …...

MySQL运维

目录 1、日志 1、错误日志 2、二进制日志 3、查询日志 4、慢查询日志 2、主从复制 搭建 1、主库配置 2、从库配置 3、分库分表 1、简介 ​编辑 1、垂直拆分 2、水平拆分 3、实现技术 2、MyCat 3、MyCat使用和配置 配置 4、MyCat分片 1、垂直拆分 2、水平拆分…...

【网络原理10】构造HTTP请求、HTTPS加密

目录 一、构造HTTP请求 ①使用form表单构造HTTP请求&#xff1a; form表单是如何提交的 form提交的缺点 ②基于ajax构造http请求 如何使用Jquery框架 二、HTTPS 运营商劫持 HTTP的加密版本&#xff1a;HTTPS ①对称加密&#xff1a;客户端和服务端使用同一把密钥&…...

Allegro如何锁定报表界面操作指导

Allegro如何锁定报表界面操作指导 用Allegro做PCB设计的时候,进行测量的时候,比如测量器件两个PIN中间的间距,如下图,会有一个报表显示 但是当运行下一个命令的时候,报表会被自动关闭掉。 但是有时我们需要报表界面仍被保留 下面介绍如何将报表界面进行锁定,不受下一个…...

基于STM32的微型电子琴设计

基于STM32的微型电子琴设计报告中的图片和文字太多了&#xff0c;全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156 第一章 总体设计1.1 系统功能1.2 主要技术性能指标第二章硬件设计2.1 整体硬件图2.2 按键模块2.3 扬声器模块2.4 显示模块2.5 主控模块第三章…...

Shell输入输出重定向

一、文件描述符 文件描述符是一个非负整数。它是一个索引值&#xff0c;指向进程打开的文件。 Linux 程序在执行任何形式的 I/O 操作时&#xff0c;都是在读取或者写入一个文件描述符。 每个文件描述符会与一个打开的文件相对应 不同的文件描述符也可能指向同一个文件 在L…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...