C指针之舞——指针探秘之旅

博客主页:折枝寄北-CSDN博客

专栏内容:C语言学习专栏icon-default.png?t=O83Ahttps://blog.csdn.net/2303_80170533/category_12794764.html?spm=1001.2014.3001.5482

指针基础学习 在之前的博客文章中,简单总结了指针的基础概念

我们知道了指针的概念:

1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。

2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。

3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。

4. 指针的运算。

今天对指针进行扩充学习并加深理解

1. 字符指针

1.1字符指针定义及其格式

在指针的类型中我们知道有一种指针类型为字符指针 char* ;

字符指针使用格式如下:

//一般使用情况:
int main()
{char ch = 'w';char* pc = &ch;*pc = 'w';return 0;
}//第二种使用情况:
int main()
{const char* pstr = "hello world.";//这里是把一个字符串放到pstr指针变量里了吗?printf("%s\n", pstr);return 0;
}

代码 const char* pstr = "hello world.";很容易让人误以为是把字符串 hello world 放到字符指针 pstr 里了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。

1.2字符指针应用示例

知道字符指针存储的是字符串的字符首元素地址,我们通过一道题目来进行验证。

#include <stdio.h>
int main()
{char str1[] = "hello world.";char str2[] = "hello world.";const char *str3 = "hello world.";const char *str4 = "hello world.";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;
}

这里最终输出的是:

这里str3和str4指向的是一个同一个常量字符串(指向同一块地址区域)     C/C++会把常量字符串存储到单独的一个内存区域,当成两个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。

2. 指针数组

2.1指针数组定义及其格式

定义:指针数组是一个存放指针的数组。

指针数组使用格式如下:

int main()
{const char* arr[4] = { "hello","world","come","back" };int i = 0;for (i = 0; i < 4; i++){printf("%s\n", arr[i]);}return 0;
}

2.2指针数组应用示例

示例:打印数组元素

int main()
{const char* arr[4] = { "hello","world","come","back" };int i = 0;for (i = 0; i < 4; i++){printf("%s\n", arr[i]);}return 0;
}int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };int arr4[] = { 4,5,6,7,8 };int* arr[4] = { arr1,arr2,arr3,arr4 };int i = 0;for(i = 0; i < 4; i++){int j = 0;for (j = 0; j < 5; j++){//printf("%d ", arr[i][j]);printf("%d ", *(arr[i]+j));//arr[i]+j是地址,*()--->进行解引用}printf("\n");}return 0;
}

代码结果为:

通过一个简图来理解如何存放指针数组

3. 数组指针

3.1数组指针定义及其格式

字符指针---存放字符地址的指针---char*

整型指针---存放整型地址的指针---int*

浮点型指针---存放浮点型地址的指针---float*  double*

定义:存放指向数组地址的指针,指向数组的指针。

数组指针使用格式如下:

int main()
{//字符指针char ch = 'w';char* pc = &ch;//整型指针int num = 10;int* pi = &num;//数组指针int arr[10] = {0};//pa就是一个数组指针int (*pa)[10] = &arr;//数组指针的形式return 0;
}

3.2数组指针应用示例

示例1:打印数组(用数组指针)

void print1(int arr[3][4], int r, int c)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf("%d ", arr[i][j]);}printf("\n");}printf("\n");
}void print2(int(*p)[4], int r, int c)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf("%d ", (*(p + i))[j]);}printf("\n");}
}int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };print1(arr, 3, 4);print2(arr, 3, 4);return 0;
}

代码结果如下:

用一个简图来理解如何访问数组:

3.3数组名和&数组名有何不同

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%p\n", arr);printf("%p\n", &arr[0]);printf("%p\n", &arr);return 0;
}

运行上面的代码,得出的结果一致,但是实质是不一样的。

对代码进行修改(加一),观察有何不同

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%p\n", arr);printf("%p\n", arr+1);printf("%p\n", &arr[0]);printf("%p\n", &arr[0]+1);printf("%p\n", &arr);printf("%p\n", &arr+1);return 0;
}

观察代码运行结果我们可以得出:

printf("%p\n", arr);  int*
printf("%p\n", arr+1);  地址加4

printf("%p\n", &arr[0]);  int*
printf("%p\n", &arr[0]+1);  地址加4

printf("%p\n", &arr);  int(*)[10]
printf("%p\n", &arr+1);  地址加40

综上可得:

数组名--数组首元素的地址

&数组名--是数组的地址

二者在值的大小上是一致的,但是二者的意义不同

完整代码片段及解释:


int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//&arr取出的是数组的地址,只有数组的地址才需要数组来接收int(*p)[10] = &arr;                            //数组名-数组首元素的地址//&数组名-是数组的地址//二者从值的大小来看是一致的,但是二者的意义不一样。printf("%p\n", arr);printf("%p\n", arr+1);//+4printf("%p\n", &arr[0]);printf("%p\n", &arr[0]+1);//+4printf("%p\n", &arr);//int(* )[10]printf("%p\n", &arr+1);//+40,跳过了整个数组char arr[5];char(*pa)[5] = &arr;return 0;
}

指针数组是一个存放指针的数组。 这里我们再复习一下,下面所提及的都是什么意思?

1. int arr[5];//整型数组,数组有5个元素

2. int *par1[10];//指针数组,数组10个元素,每个元素是int*类型

3. int (*parr2)[10];//数组指针,该指针指向一个数组,数组有10个元素,每个元素是int类型

4.int(*parr3[10])[5];//parr3是数组,数组有10个元素,数组每个元素的类型是int(*)[5]的数组指针类型

简图理解4.

4. 数组传参和指针传参

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

4.1 一维数组传参

#include<stdio.h>
void test(int arr[])//ok(√)
{}void test(int arr[10])//ok(√)
{}void test(int* arr)//ok(√)
{}void test2(int *arr2[20])//ok(√)
{}void test2(int **arr)//ok(√)
{}int main()
{int arr[10] = { 0 };int* arr2[20] = { 0 };test(arr);test2(arr2);return 0;
}

4.2二维数组传参

void test(int arr[3][5])//ok(√)
{}void test(int arr[][])//行可以省略,列不可以省略不写(×)
{}void test(int arr[][5])ok(√)
{}//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。void test(int *arr)//(×)
{}
void test(int* arr[5])//(×)
{}void test(int (*arr)[5])//(×)
{}void test(int **arr)//(×)
{}int main()
{int arr[3][5] = { 0 };test(arr);
}

4.3一级指针传参

#include <stdio.h>
void print(int* p, int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d\n", *(p + i));}
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9 };int* p = arr;int sz = sizeof(arr) / sizeof(arr[0]);//一级指针p,传给函数print(p, sz);return 0;
}

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

例如:

void test(int *p)

{}

int a=0;

int *p=&a;

int arr[10];

test(arr);

test(&a);

test(p);

4.4二级指针传参

#include<stdio.h>
void test(int** ptr)
{printf("num=%d\n", **ptr);
}int main()
{int n = 10;int* p = &n;int** pp = &p;test(pp);test(&p);return 0;
}

当函数的参数为二级指针的时候,可以接收什么参数?

可以接受:二级指针,指针数组的数组名.....

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:腾讯云自媒体同步曝光计划 - 腾讯云开发者社区-腾讯云

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

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

相关文章

[Qt platform plugin问题] Could not load the Qt platform plugin “xcb“

Qt platform plugin 是 Qt 应用程序启动时加载的插件。不同的平台有不同的插件。 常见的插件有:linuxfb Wayland xcb 简单来说就是启动一个GUI程序, 离不开这些插件.选择其中一个就好 出现这个问题要么就是没有插件&#xff0c;要么就是插件依赖的库没有。 要么就是插件选则的…

Skywalking搭建-来自于图灵课堂

Skywalking主要用于链路追踪&#xff0c;日志收集查看&#xff0c;异常日志查看&#xff0c;服务监控弱一些&#xff0c;服务器监控可以使用prometheus 一、搭建服务端&#xff0c;使用startup.bat启动 配置持久化&#xff0c;如果是用mysql持久化&#xff0c;拷贝mysql链接包…

Relaxcert SSL证书申请与自动续签之IIS

Relaxcert SSL证书申请与自动续签之IIS 1.下载安装自动续签程序2.配置客户端秘钥3.HTTP站点升级HTTPS4.关于SSL自动续签 Relaxcert SSL证书申请与自动续签工具 控制台地址 https://cert.relaxcert.com 文档地址 https://doc.relaxcert.com 1.下载安装自动续签程序 登录控制台…

spi 回环

///tx 极性0 &#xff08;sclk信号线空闲时为低电平&#xff09; /// 相位0 (在sclk信号线第一个跳变沿进行采样) timescale 1ns / 1ps//两个从机 8d01 8d02 module top(input clk ,input rst_n,input [7:0] addr ,input …

IDEA旗舰版编辑器器快速⼊门(笔记)

简介&#xff1a;javaweb开发必备软件之IDEA期间版介绍 DEA编辑器器版本介绍 官⽹网&#xff1a;https://www.jetbrains.com/地址&#xff1a;https://www.jetbrains.com/idea/download/#sectionmac DEA 分社区版(Community) 和 旗舰版(Ultimate)&#xff0c;我们做JavaWeb开…

WPF的基础控件详解

WPF的基础控件详解 在WPF学习中 基本控件是最简单也是最基础的东西。也是很初学者容易忽略的 本此笔记教程主要针对WPF中基础控件使用和应用进行手把手教学&#xff0c;如果学习了此笔记对你有帮助记得一键三连哦~~~~ TextBlock 基本用法 长字串处理 LineBreak标籤在指定的地…

MySQL的聚簇索引和二级索引

索引按照物理实现方式&#xff0c;索引可以分为 2 种&#xff1a;聚簇&#xff08;聚集&#xff09;和非聚簇&#xff08;非聚集&#xff09;索引。也可以把非聚集索引称为二级索引或者辅助索引。 一.聚簇索引 聚簇索引并不是一种单独的索引类型&#xff0c;而是一种数据存储方…

2.5D视觉——Aruco码定位检测

目录 1.什么是Aruco标记2.Aruco码解码说明2.1 Original ArUco2.2 预设的二维码字典2.3 大小Aruco二维码叠加 3.函数说明3.1 cv::aruco::detectMarkers3.2 cv::solvePnP 4.代码注解4.1 Landmark图说明4.2 算法源码注解 1.什么是Aruco标记 ArUco标记最初由S.Garrido-Jurado等人在…

能源革命持续发力,华普微隔离器助力储能行业“向绿向新”

能源是工业的粮食&#xff0c;是国民经济的命脉&#xff0c;亦是实现可持续发展的关键之处。在各国“双碳”目标战略的引领下&#xff0c;能源革命正全面席卷而来&#xff0c;而加速培育能源新质生产力&#xff0c;构建清洁低碳、安全高效的新型能源体系&#xff0c;已成为全球…

微信小程序-prettier 格式化

一.安装prettier插件 二.配置开发者工具的设置 配置如下代码在setting.json里&#xff1a; "editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","prettier.documentSelectors": ["**/*.wxml"…

sapiens推理的安装与使用

文章目录 1、安装1.1 克隆代码库1.2 设置 Sapiens-Lite 的代码路径1.3 创建 Conda 环境并安装必要的依赖1.4 下载模型检查点 2、推理 sapiens&#xff0c;是meta发布的以人为中心的视觉大模型&#xff0c;"sapiens"这个词来源于拉丁语&#xff0c;意为“智慧的”或“…

leetcode-44-通配符匹配

题解&#xff1a; 代码&#xff1a; 参考&#xff1a; (1)牛客华为机试HJ71字符串通配符 (2)leetcode-10-正则表达式匹配

Linux守护Pythom脚本运行——Supervisor学习总结

Supervisor能做什么&#xff1f; 在工作中有时会遇到在Linux服务器上编写各种脚本来实现日志的推送、数据的传输、流量的监控等&#xff0c;这些脚本在整个系统运行中也需要和其他服务端应用程序一样持续且稳定运行&#xff0c;为了达到这种目的就需要使用进程守护工具来对正在…

C++ | Leetcode C++题解之第565题数组嵌套

题目&#xff1a; 题解&#xff1a; class Solution { public:int arrayNesting(vector<int> &nums) {int ans 0, n nums.size();for (int i 0; i < n; i) {int cnt 0;while (nums[i] < n) {int num nums[i];nums[i] n;i num;cnt;}ans max(ans, cnt);…

SpringBoot总结

一、Spring\SpringBoot\SpringCloud Spring&#xff1a;Spring是SpringBoot和SpringCloud的基础。Spring是一个广泛使用的企业级 Java 应用程序框架&#xff0c;提供了应用开发的核心功能&#xff0c;如依赖注入、AOP&#xff08;面向切面编程&#xff09; 等&#xff0c;旨在简…

Tailscale 自建 Derp 中转服务器

文章目录 为什么要建立 Derp 中转服务器&#xff1f;安装 Go 环境通过 Go 安装 Derp处理证书文件自签一个域名启动 DerpIPV6 的支持防止 Derp 被白嫖以上的操作命令合集自建 Headscale 添加 Derp参考 为什么要建立 Derp 中转服务器&#xff1f; Tailscale 使用的算法很有趣: 所…

vue实现展示并下载后端返回的图片流

// 点击下载 downLoadCode() {const image new Image();image.setAttribute("crossOrigin", "anonymous");image.onload () > {const canvas document.createElement("canvas");canvas.width image.width;canvas.height image.height;c…

Docker: ubuntu系统下Docker的安装

安装依赖 操作系统版本 Ubuntu Kinetic 22.10Ubuntu Jammy 24.04 (LTS)Ubuntu Jammy 22.04 (LTS)Ubuntu Focal 20.04 (LTS)Ubuntu Bionic 18.04 (LTS) CPU架构支持 ARMx86_64 查看我们的系统版本信息 uname -a通过该命令查得cpu架构是x86_64的&#xff1b; cat /etc/*re…

极速入门数模电路

一. 认识数模元器件 1.1 面包板 1.2 导线 一般使用红色导线表示正极&#xff0c;黑色导线表示负极。 1.3 纽扣电池 1.4 电池座 1.4 LED灯 1.5 数码管 1.6 有源蜂鸣器 1.7 扬声器 1.8 电容 电容接电池之后可以充电&#xff0c;充完电后电容接LED灯可以放电。 1.9 电阻 1.1…

如何合理设计一套springcloud+springboot项目中的各个微服务模块之间的继承关系的最优方案

文章目录 一、模块化设计所遵循的原则二、项目架构设计三、各个模块作用说明3.1 core 模块3.2 common 模块3.3 generatorcode模块3.4 business 模块3.5 web 模块3.6 admin 模块3.7 父pom 四、采用import引入SpringBoot 在springcloud微服务项目中经常用到多模块化的架构设计&am…