当前位置: 首页 > 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…...

华为OD机试-运维日志排序

文章目录题目描述输入描述输出描述&#xff1a;示例Java 代码实现题目描述 运维工程师采集到某产品线网运行一天产生的日志n条&#xff0c;现需根据日志时间先后顺序对日志进行排序&#xff0c;日志时间格式为H:M:S.N。 H表示小时(0~23) M表示分钟(0~59) S表示秒(0~59) N表…...

1Kotlin基础知识

1 变量 1.1 用法 Kotlin中的变量定义有2个关键字&#xff0c;val和var val用来定义不可变变量&#xff0c;第一次赋值后就不能再被修改了&#xff0c; var定义可变变量&#xff0c; 随便修改。一个好的编程习惯是&#xff0c; 能用val的就不要用var&#xff0c; 原因是安全&a…...

Redis Lua脚本

文章目录一.引言二.eval简介三.lua数据类型和redis数据类型之间转换四.脚本的原子性五.错误处理六.纯函数脚本七.选择内部脚本一.引言 eval和evalsha命令使用内置的lua解释器&#xff0c;可以对lua脚本进行求值。 二.eval简介 第一个参数是一段脚本程序第二个参数是参数的个…...

web自动化测试-执行 JavaScript 脚本

JavaScript 是一种脚本语言&#xff0c;有的场景需要使用 js 脚本注入辅助我们完成 Selenium 无法做到的事情。 当 webdriver 遇到无法完成的操作时&#xff0c;可以使用 JavaScript 来完成&#xff0c;webdriver 提供了 execute_script() 方法来调用 js 代码。 执行 js 有两种…...

libevent笔记——简单介绍

背景 libevent libevent – an event notification library 官方定义&#xff1a;libevent是一个事件通知的库。更详细的介绍参考官方的就够了&#xff0c;这里我摘抄一下&#xff0c;并做一些注释 The libevent API provides a mechanism to execute a callback function whe…...

C++学习笔记-多态

多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c; 具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的状态 。 举个例子&#xff1a;比如 买票这个行为 &#xff0c;当 普通人 买票时&#xff0c;是全价买票&#xff1b…...

5632: 三角形

描述平面坐标系下&#xff0c;给定不共线的三个点组成一个三角形&#xff0c;问三角形最短的边长和最长的边长各为多少&#xff1f;输入输入包含3行&#xff0c;每行两个整数&#xff0c;表示一个点的坐标x和y。输出输出包括2个小数&#xff0c;分别为最短的边长和最长的边长。…...

Java基础--IO操作

一、IO原理及分类 一、IO原理 1、I/O是Input/Output的缩写&#xff0c;I/O技术是非常实用的技术&#xff0c;用于处理设备之间的数据传输&#xff0c;如读写文件&#xff0c;网络通信等。 2、java程序中对于数据的输入/输出操作一般都是以流的方式进行 3、java.io包下提供各…...

C++多线程

目录一、C线程库1. 认识thread类2. 线程函数的参数3. this_thread二、原子操作三、C互斥锁1. mutex2. lock_guard3. unique_lock四、C条件变量1. condition_variable2. 实现两个线程交替打印奇偶数一、C线程库 1. 认识thread类 在C11之前没有多线程的概念&#xff0c;涉及到的…...

【Arduino使用nRF24L01 】

【Arduino使用nRF24L01 】 1. 概述2. nRF24L01 收发器模块2.1工作原理2.2 NRF24L01模块变体2.3 nRF24L01 模块引脚排列3. 如何将 nRF24L01 连接到 Arduino3.1 原理接线图3.2 Arduino 和 nRF24L01 代码3.3 代码说明4. 故障排除5. 两个NRF24L01和Arduino进行双向无线通信5.1 nRF2…...